Handler机制详解、源码分析、及其内存泄漏的处理

一、handler的消息机制

一句话:handler通过sendMessage发送Message到MessageQueue,Looper通过loop()不断地轮询MessageQueue,调用Handler的dispatchMessage将Message通知给Callback回调,在回调中handleMessage()方法接收消息并处理UI更新。

二、源码分析

handler通过sendMessage来发送Message消息,通过enqueueMessage方法将Message加入到MessageQueue中,MessageQueue是以链表的形式存储Message的,来看一下Handler的源码:


Handler机制详解、源码分析、及其内存泄漏的处理_第1张图片
Handler机制详解、源码分析、及其内存泄漏的处理_第2张图片
Handler机制详解、源码分析、及其内存泄漏的处理_第3张图片
Handler机制详解、源码分析、及其内存泄漏的处理_第4张图片

在MessageQueue中,


Handler机制详解、源码分析、及其内存泄漏的处理_第5张图片
Handler机制详解、源码分析、及其内存泄漏的处理_第6张图片

读源码可以发现message是以链表的形式串联在一起的,将上述代码形象转化成下图:


Handler机制详解、源码分析、及其内存泄漏的处理_第7张图片

通过上述流程,已经将新的Message加入到了MessageQueue中,再来看,这个MessageQueue到底是从哪来的是在哪个线程中的?带着疑问去找Handler


Handler机制详解、源码分析、及其内存泄漏的处理_第8张图片

我们回到Handler中,在构造方法中找到了MessageQueue的出处,是通过Looper.myLooper()获取到Looper对象,再从中获取的消息队列。那么Looper又是从哪里来的又属于哪个线程呢?我们继续看Looper


通过ThreadLocal(线程局部变量)来get到当前线程的Looper,即与Handler创建的线程一致,这样,我们已经理清Handler是如何将Message发送到MessageQueue中的并以链表形式存储的,同时也知道了轮询消息队列的Looper是与Handler处于同一线程,这也是处理Handler发送消息的Looper唯一性的原因。接下来,我们来看一下Looper又是如何处理消息队列中的消息的。

查看Looper的源码,其中loop()是启动轮询的方法:


Handler机制详解、源码分析、及其内存泄漏的处理_第9张图片
Handler机制详解、源码分析、及其内存泄漏的处理_第10张图片

首先拿到同线程的Looper并获取到其中的消息队列,使用死循环来遍历MessageQueue中的Message,其中msg.target获取到与message关联的Handler,调用Handler的dispatchMessage方法,再回到Handler中:


Handler机制详解、源码分析、及其内存泄漏的处理_第11张图片
Handler机制详解、源码分析、及其内存泄漏的处理_第12张图片
Handler机制详解、源码分析、及其内存泄漏的处理_第13张图片

可以知道,我们在创建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

不多说,直接上代码:


Handler机制详解、源码分析、及其内存泄漏的处理_第14张图片

原创文章,转载请注明出处,谢谢!

你可能感兴趣的:(Handler机制详解、源码分析、及其内存泄漏的处理)