android异步消息机制总结与思考

作者: Dynamic_2018 | 来源:发表于2017-10-30 17:21 被阅读50次

android异步消息机制总结与思考

handler机制.PNG
上图来自郭霖老师的博客,画的很形象,我就不自己造轮子了
郭霖老师博客传送门

现在在看这幅图,应该已经很清楚了。为什么可以实现不同线程间的消息传递。因为handler发送msg的地方虽然是可以在不同的线程,但是最后发送到的msgQueue都是在该looper绑定的线程里面。
就拿主线程的mhandler来讲,它一定和smainLooper绑定的,smainLooper对应主线程。不管mhandler在哪个thread发送msg(send,post等方式),最后都是放在了主线程的msgQueue里面。
一切的一切都是因为发送消息的地方和处理消息的地方在不同线程,所以实现了线程间的通信。那么再往上想一下,为什么发消息的地方会不一样,自然而然的想到了handler.sendMessage()的地方;只要在线程里这个handler对象拿到了,就可以发送消息。

以为到这里就结束了吗

handler消息机制 带来的问题.png

handler带来的内存泄漏问题:

先分析下原因

之前提到过,msgQueue里面拿出msg后可以找到对应的handler去分发处理,是因为msg持有handler的引用。如果hadnler持有是内部类或者匿名类,那么handler和外部类(一般是所在的activity)就有联系,gc工作的时候,就不能把这个activity回收掉。
当然如果msg发送后,马上就被处理掉,影响也不严重。
但是如果是sendMessgaeDelay()延迟了10s,那么至少在这10s内,想要回收这个acitvity是不可能的。就导致了内存泄漏。

避免的办法

根本原因是msg持有handler的引用。handler再持有activity的引用。msg没处理完,这个activity就不能被GC回收。msg持有handler的引用,这个是不能做修改的,源码就是那样设计的。那么我们能做出改变的就是handler和activity(外部类)的联系了。
内部类不依赖外部类,自然就想到了静态内部类。把handler声明成static,这样handler就不依赖activity(外部类)存在了,代价就是静态内部类只能使用外部类的静态方法,访问静态成员变量。
通用做法静态类加弱引用

public static class MyHandler extends Handler {
        WeakReference<Activity> activity;

        public MyHandler(WeakReference<Activity> activity) {
            this.activity = activity;
        }

另外一种方式就是在退出activity的时候把messageQueue的消息移除掉,调用handler.removeCallBackAndMessage(null)方法。

loop循环是否会导致anr的思考:

loop是否会导致anr参考Android中为什么主线程不会因为Looper.loop()里的死循环卡死?;
首先要明确造成anr的原因:应用未响应。指主线程事件得不到处理,或者处理超时(一般是5s)。
Looper.loop();虽然是一个循环,但是它并不会导致事件响应超时。只是负责取出来分发,具体耗时多少并不是在loop这里。反而由于它一直在loop,其他事件才得以在主线程分发。

如果有问题的地方请指出,一起交流学习成长

相关文章

网友评论

    本文标题:android异步消息机制总结与思考

    本文链接:https://www.haomeiwen.com/subject/qkmppxtx.html