一、handler的消息机制
一句话:handler通过sendMessage发送Message到MessageQueue,Looper通过loop()不断地轮询MessageQueue,调用Handler的dispatchMessage将Message通知给Callback回调,在回调中handleMessage()方法接收消息并处理UI更新。
二、源码分析
handler通过sendMessage来发送Message消息,通过enqueueMessage方法将Message加入到MessageQueue中,MessageQueue是以链表的形式存储Message的,来看一下Handler的源码:
在MessageQueue中,
读源码可以发现message是以链表的形式串联在一起的,将上述代码形象转化成下图:
通过上述流程,已经将新的Message加入到了MessageQueue中,再来看,这个MessageQueue到底是从哪来的是在哪个线程中的?带着疑问去找Handler
我们回到Handler中,在构造方法中找到了MessageQueue的出处,是通过Looper.myLooper()获取到Looper对象,再从中获取的消息队列。那么Looper又是从哪里来的又属于哪个线程呢?我们继续看Looper
通过ThreadLocal(线程局部变量)来get到当前线程的Looper,即与Handler创建的线程一致,这样,我们已经理清Handler是如何将Message发送到MessageQueue中的并以链表形式存储的,同时也知道了轮询消息队列的Looper是与Handler处于同一线程,这也是处理Handler发送消息的Looper唯一性的原因。接下来,我们来看一下Looper又是如何处理消息队列中的消息的。
查看Looper的源码,其中loop()是启动轮询的方法:
首先拿到同线程的Looper并获取到其中的消息队列,使用死循环来遍历MessageQueue中的Message,其中msg.target获取到与message关联的Handler,调用Handler的dispatchMessage方法,再回到Handler中:
可以知道,我们在创建Handler时所实现的Callback回调在此时被调用到,即Looper轮询任务后,通过Handler的dispatchMessage方法通知Callback执行handleMessage方法,这样我们在handleMessage中接收消息来更新UI。
以上完成了Handler的整个消息传递机制,我们再来总结下:
1、在主线程中创建Handler,在Handler的构造方法中获取到当前线程的Looper和MessageQueue。
2、当调用handler.sendMessage(Message msg)方法时,通过Handler的enqueue方法将Message发送到MessageQueue中,MessageQueue中的消息是以链表的形式连在一起的。
3、Looper通过loop()方法轮询MessageQueue中的消息,通过调用Handler的dispatchMessage()方法来通知Callback回调。
4、在Handler的Callback回调中实现handleMessage(Message msg)方法,接收message,进而更新主线程UI。
关键点:
1、Handler、Looper、MessageQueue处于同一个线程,为主线程(HandlerThread的Looper是在子线程,使用HandlerThread用来分担主线程中Looper的压力,同时提高优先级)。
2、MessageQueue中的Message以链表的形式连在一起,先进先出。
3、Handler中通过ThreadLocal来获取当前线程的Looper,从而保证了Looper的唯一性,一个Handler发送的消息不会有多个Looper来进行处理。
4、Message中msg.target获取到Message绑定的Handler,也就是Message持有着Handler的引用。
三、Hanlder内存泄漏的问题及解决
导致内存泄漏的原因是非静态内部类持有外部类引用,当外部类Activity销毁时,该引用没有得到及时释放,导致该Activity无法回收,从而造成内存泄漏。
解决方案:
1、将Handler改为静态内部类,用static修饰
2、内部使用Activity的弱引用
3、在Activity的onDestroy()方法中removeCallback
不多说,直接上代码:
原创文章,转载请注明出处,谢谢!
网友评论