android Handler消息处理源码剖析

1、什么是Handler

A Handler allows you to send and process Message and Runnable objects associated with a thread's MessageQueue. Each Handler instance is associated with a single thread and that thread's message queue. When you create a new Handler, it is bound to the thread / message queue of the thread that is creating it --from that point on, it will deliver messages and runnables to that message queue and execute them as they come out of the message queue.

Handler允许你发送和处理Message(消息)/Runnable对象到当前线程的MessageQueue(消息队列)中。每个Handler实体对象都和当前所处线程的一个消息队列进行关联。当你创建一个新的Handler,这个Handler就和当前所处的线程和消息队列绑定在一起,从这个时刻开始,该Handler发送消息和Runnable对象到消息队列,在从MessageQueue取出消息的那一刻就开始执行消息。

2、Handler可以做什么

Handler是Android的一种消息处理机制,这种机制主要是为了解决Android应用中多线程的问题:在Android中不允许Activity新启动的线程访问该Activity里的UI组件,这样会导致新启动的线程无法改变UI组件的属性值。但实际开发中,很多地方需要在工作线程中改变UI组件的属性值,比如下载网络图片、动画等等。

Handler有两个作用:

(1)在工作线程中发送消息

(2)在UI线程中取出和处理消息

3、Handler提供的API

Handler提供两种方式将消息发送的队列:post和sendMessage。

Post:Post允许把一个Runnable对象加入到MessageQueue中,方法有post、postAtTime、postDelayed。

SendMessage:sendMessage允许把一个包含消息数据的Message放入MessageQueue中。包含sendEmptyMessage、sendMessage、sendMessageAtTime、sendMessageDelayed。

4、支撑Handler机制的架构图

android Handler消息处理源码剖析
架构图

可以看到支撑Handler消息处理机制需要至少Handler、Message、MessageQueue、Looper四个类。

5、Handler、MessageQueue、Looper、Message的类图关系

android Handler消息处理源码剖析
类图关系

Handler:消息的真正处理类,具有发送消息、处理消息、移除消息的功能。依赖于MessageQueue和Looper;mQueue是MessageQqeue消息队列,通过sendMessage或者post方法发送的Message就存放在这个队列里面。mLooper是Looper消息调度器,用于循环取出mQueue中的Message。

MessageQueue:mMessages存放了所有的Message,以链表的形式存储。

Looper:用于循环从MessageQueue中取得Message,然后把、执行Message对应target的dispatchMessage方法。依赖于MessageQueue;mThreadLocal用于存放当前线程对应的Looper;sMainLooper表示UI主线程的Looper;mQueue是所有消息的队列。

Message:代表一条消息,依赖于Handler进行消息处理,对应一个Handler类型的target,在加入队列之前就会进行target设置。

6、Message消息从发送到运行源码解析

android Handler消息处理源码剖析
handler使用示例

通常情况下,我们通过创建一个Handler和一个Message,然后调用sendMessage来发送消息。流程图如下:

android Handler消息处理源码剖析
发送Message序列图

在创建Handler的时候,会触发Handler如下构造函数,该构造函数首先调用Looper.myLooper()创建一个Looper对象。

android Handler消息处理源码剖析
new Handler()

Looper.myLooper()实现如下,myLoop方法取得当前线程保持的Looper对象。

android Handler消息处理源码剖析
Looper.myLooper()

myLooper()如果返回空值,在创建Handler时就会直接crash。因此在创建Handler时需要先创建Looper对象,并设置到Looper的sThreadLocal,;sTheadLocal用来保存当前线程的Looper对象,那当前线程的Looper对象是什么时候设置的呢?跟踪代码发现Looper.prepare方法会创建一个Looper,Looper对象在创建时会关联一个mQueue对象,最后将Looper设置到ThreadLocal,从此每个线程就会有自己的Looper对象。

android Handler消息处理源码剖析
Looper.prepare()
android Handler消息处理源码剖析
Looper构造函数

因此在创建Handler之前需要先调用Looper.prepare()为当前线程创建一个Looper对象。创建完Looper对象后,就将该Looper的MessageQueue对象赋值给Handler,这样sendMessage()发送的Message就直接交给Looper的MessageQueue对象。

那么问题来了,当一个Message放入MessageQueue中后,谁来运行它呢?又是什么时机来运行的呢?我们似乎没有看到从MessageQueue取Message并运行的流程。上面我们提到了Looper类是不停地循环取Message的帮助类;没错,Android内部通过Looper的loop方法来不停地遍历MessageQueue。代码如下:

android Handler消息处理源码剖析
Looper.loop()

当调用了Looper.loop方法后,首先通过myLooper()方法取得当前线程的Looper对象,也就是sThreadLocal中保存的值;然后取得当前线程Looper对象的mQueue,最后通过无线循环在取出mQueue的Message;运行Message对应target(Handler)的dispatchMessage方法。

因此,要实现一个Handler的正确做法应该如下:

android Handler消息处理源码剖析
正确使用Handler的方法

在loop()调用后会运行每个message.target.dispatchMessage()方法,那target是在什么时候设置的呢?在调用Handler的enqueueMessage方法时就会将自身设置给Message对象。

android Handler消息处理源码剖析
sendMessage最终调用的方法

这样当Looper.loop()取得Message后就会直接调用handler的dispatchMessage(),该函数其实就是调用handleMessage方法,也就是我们在创建Handler时需要自己实现的方法。

android Handler消息处理源码剖析
handler最终执行Message的方法

如果用户在创建Message的时候传入了Callback就调用Message的Callback,Callback是一个Rnnable接口。如果没有传入Callback,就查看当前Handler在创建时是否指定了Callback,Handler的Callback只是一个handleMessage接口;如果都没有直接调用handler的handMessage()方法,这就是我们每次创建Handler都需要自己实现handlerMessage()的原因。

上面提到了在创建Handler时需要先调用Looper.prepare(),但是我们在实际编写代码中,例如在Activity中创建Handler没有主动调用Looper.prepare(),却没有报"Can't create handler inside thread that has not called

Looper.prepare()",这是因为Activity属于UI主线程,在APK启动时系统已经帮我们建好Looper了,代码就在AvtivityThread中,ActivityThread的main函数是整个APK运行的入口如下所示:

android Handler消息处理源码剖析
ActivityThread main
上一篇:ios:CGContextRef 渲染中文问题


下一篇:ios-表视图-demo5-索引