理解 Handler 框架
本篇我们先从 HandlerThread
讲起,然后整体上看看 Handler 框架。
从 HandlerThread
谈起
HandlerThread
是 Android API 的一部分,目的是让我们更方便地在工作线程使用 Handler 框架,它的实现并不是很复杂,我们直接看代码:
1 | // frameworks/base/core/java/android/os/HandlerThread.java |
如果想在工作线程中使用 Handler 框架,关键的动作只有两个:
- 执行
Looper.prepare()
对Looper
进行初始化 Looper.loop()
开始事件循环。
上面代码段中间的 synchronized 块,需要结合 getLooper()
来看:
1 | // frameworks/base/core/java/android/os/HandlerThread.java |
创建了一个基于 Handler 框架的线程后,我们需要通过 Handler
把任务 post 到工作线程。为了拿到这个 Handler
,有两个方法可以选择:
- 继承
HandlerThread
并重写onLooperPrepared()
方法。在这个方法中,可以直接创建Handler
(这个方法运行在工作线程,而使用Handler
的一般是这个工作线程之外的其他线程,需要注意Handler
实例的可见性)。 - 创建
HandlerThread
后,调用handlerThread.getLooper()
拿到对应的Looper
,接着new Handler(looper)
。
我们重点关注第二种方法。它的问题在于,getLooper
的时候,对应的 Looper
可能还没有初始化。这种情况下,调用线程就需要等待,直到 Looper
完成初始化。
在 getLooper()
中,如果 mLooper == null
,说明还有初始化,调用 wait()
开始等待。而在 run()
中,初始化完成后调用 notifyAll()
唤醒所有等待线程(可能不止一个线程在等待)。
Handler
框架的使用就讲到这里,下面我们看看它的实现。
框架概览
总的来说,就是 Looper
不断地从 MessageQueue
里拿出 Message
执行。而 Message
是通过 Handler
插入 MessageQueue
的。
Looper
的构造
首先我们看看 Looper.prepare()
:
1 | //frameworks/base/core/java/android/os/Looper.java |
prepare()
方法做的事很简单,就是创建一个 Looper
实例,然后放到 sThreadLocal
中。普通的 Looper
是允许退出的,而主线程则不行:
1 | //frameworks/base/core/java/android/os/Looper.java |
在它的构造函数,则创建了一个 MessageQueue
:
1 | //frameworks/base/core/java/android/os/Looper.java |
Looper
中的循环
执行 Looper.prepare()
后,就可以使用 Looper.loop()
开始事件循环:
1 | //frameworks/base/core/java/android/os/Looper.java |
Looper.loop()
所做的,就是在一个循环中,不断地从 MessageQueue
取出 Message
并执行。
我们先看看 msg.target.dispatchMessage(msg)
, msg.target
就是 Handler
:
1 | //frameworks/base/core/java/android/os/Handler.java |
- 如果
Message
中的Runnable
(这里的msg.callback
) 不为空,就执行runnable.run()
- 如果
mCallback
不为空,就给mCallback
处理。mCallback
通过构造函数设置 - 以上两个都不成立,调用自身的
handleMessage()
处理,子类可以重写handleMessage()
现在我们看 msg.recycleUnchecked()
。从字面意思看,应该是回收这个 Message
:
1 | //frameworks/base/core/java/android/os/Message.java |
果然,recycleUnchecked
将自己(Message
对象)放在了以 sPool
为头结点的列表中。缓存的对象可以使用 Message.obtain()
再拿出来使用:
1 | //frameworks/base/core/java/android/os/Message.java |
Looper
的退出
前面我们看到,Looper.loop()
里面有一个无限循环,默认情况下,他永远不会退出。但是,某些时候,我们还是希望对应的线程能够终止,以回收一些资源。
需要 Looper
退出时,执行 Looper.quit()
即可:
1 | //frameworks/base/core/java/android/os/Looper.java |
quit()
执行后,会清空 MessageQueue
中剩余的未执行的 message
,然后唤醒在 MessageQueue
上等待的线程。线程醒来后,next()
方法将会返回 null
,于是,Looper.loop()
就返回了。
1 | //frameworks/base/core/java/android/os/Looper.java |
Handler
的使用
最后,我们看看 Handler
。这里我们只分析带 Looper
参数的构造函数版本,实现上很简单:
1 | //frameworks/base/core/java/android/os/Handler.java |
我们通过 handler
向 looper 线程发送 Message
后,最终会到达 sendMessageAtTime
方法:
1 | public boolean sendMessageAtTime(Message msg, long uptimeMillis) { |
这里可以看到,handler
通过 queue.enqueueMessage()
将 Message
放到了 MessageQueue
中。并且,把 msg.target
设置为自己。还记得吗:在 Looper
中有这么一行代码:
1 | //frameworks/base/core/java/android/os/Looper.java |
Looper.loop()
中使用的 msg.target
就是在 Handler
里面设置的,这样一来,某个 handler
实例发送的 message
,最终也会由自己处理。
Handler 框架到这里,基本就讲清楚了。如果你还有什么不明白的地方,最好自己对照着源码看一遍。如果看过几遍源码还不理解,可以发邮件跟我一起讨论。