Handler消息机制原理总结

1、Handler不仅能将子线程的数据传递给主线程,还可以在任意两个线程中实现数据传输。

2、通常我们在主线程中创建Handler;然后重写该Handler的handlerMessage方法。

其中Message的几个属性:

Message.what-----标识信息的int值,判断信息来自哪里。

Message.arg1/Message.arg2------初始定义传递int类型的变量

Message.obj-------用来传递任何实例化对象。

最后通过sendMessage将Message发送出去。

3、在两个子线程中通过handler发送数据。其中一个子线程初始化Handler。实现handlerMessage方法,另一个子线程通过sendMessage发送数据。需要注意的是,在初始化Handler时需要在开始创建Looper。方法为Looper.prepare()。最后还需要Looper.loop()。

如果不进行prepare()方法将报异常;不进行loop()方法将不能接收到消息。

在prepare()方法中在当前thread创建一个Looper()。ThreadLocal主要是用于维护线程的本地变量。Looper的构造函数中又创建了MessageQueue()对象。

在主线程中创建Handler不需要重新调用Looper.prepare()和Looper.loop()。是因为APP初始化都会执行ActivityThread的main方法。在这个方法中调用了Loop.prepareMainLooper()和Looper.loop()方法。

4、Handler发送消息。调用Handler不同参数发送Message最终都会调用sendMessageAtTime方法。关键方法在于enqueueMessage()方法内部调用了messageQueue的enqueueMessage()方法。

5、Message被存入MessageQueue时是将Message存到了上一个Message.next上,形成一个链式的列表,同时保证Message列表的时序性。

6、Looper.loop()方法。在调用Looper.prepare()方法之前不能调用该方法,否则抛出异常。myLooper()方法取出了当前线程的looper对象,然后从looper对象开启了一个死循环不断从looper内的MessageQueue中取出Message。只要有Message对象,就会通过Message的target调用dispatchMessage去分发消息。其中target就是我们创建的handler。

7、dispatchMessage方法。如果我们设置了callback(Runnable对象),则会直接调用handleCallback方法。比如我们经常写的runOnUiThread方法,直接调用run方法。如果msg.callback为空的话,就会调用handler的handlerMessage方法。

8、handler所创建的线程需要维护一个唯一的Looper对象,每个线程对应一个Looper,每个线程的Looper通过ThreadLocal来保证。Looper对象内部又维护唯一一个MessageQueue。所以一个线程可以有多个handler,但只能有一个Looper和一个MessageQueue。

9、handler使用过程中内存泄漏问题。

为什么会出现内存泄漏:Handler使用时用来进行线程间通信的,新开启的线程会持有Handler引用,如果在Activity等中创建Handler,并且是非静态内部类的形式,就有可能造成内存泄漏。

(1)首先,非静态内部类是会隐式持有外部类的引用,所以当其他线程持有了该Handler,线程没有被销毁,则意味着Activity会一直被Handler持有引用而无法导致回收。

(2)同时,MessageQueue中如果存在未处理完的Message,Message的target也是对Activity等的持有引用,也会造成内存泄漏。

解决方法:(1)使用静态内部类+弱引用的方式。静态内部类不会持有外部类的引用,当需要引用外部类操作时通过弱引用获取到外部类相关操作,弱引用不会造成对象回收不掉的问题。

(2)在外部类对象被销毁时,将MessageQueue消息清空,handler.removeCallbacksAndMessages(null)。

10、在使用Handler时通常使用Handler.obtainMessage()来获取Message对象,内部调用的是Message.obtain()方法,而不是直接new一个Message。

查看obtain()方法。在Message中有一个static Message变量sPool,这个变量用于缓存Message对象。不为空,返回当前的sPool。指向之前sPool的next对象。如果sPool为空,则需要创建一个新的Message(new Message)。

使用obtain获取Message对象是因为Message内部维护了一个数据缓存池,回收的Message不会立马销毁,而是放入缓存池,会优先从缓存池中获取Message,为null才会创建新的Message。每次使用完后会调用recycle回收。

11、linux层去实现阻塞式循环,有消息就去执行,没消息就休眠。queue.next()的源码里有个nativePollOnce()进入了JNI C代码里,有立即执行的message就会立即返回,没有的话nativePollOnce()无法返回,线程就会进入休眠。

原文:https://www.jianshu.com/p/d045101cffad

©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

友情链接更多精彩内容