目录:
1. 前言
在上一篇关于 Android Handler使用方法 的文章中学会了 Handler 的使用方法,然而又是知其然不知其所以然的状态,这次较深入的学习一下 Handler 的源码。
在分析源码之前,先来了解一下Message、MessageQueue、Looper这几个对象。
1.1 Message 消息
定义:是线程间通讯的数据单元,包含着描述信息及任意数据对象,发送到 Handler。
在实际使用中,我们在工作线程中通过 Handler.sendMessage(Message),将携带数据的 Message 信息发送给 Handler,然后再由 Handler 处理,根据不同的信息,通知主线程作出相对应的 UI 工作。
官方文档说明:
/**
* 定义包含着描述信息及任意数据对象的可发送到 Handler 的信息。额外包含可以不被分配的两个 int 字段及一个 Object 字段。
* 获取 Message 对象最好的方法是调用 Message.obtain() 或 调用 Handler.obtainMessage() 方法来获取,调用该方法将从可回收的对象池中获取对象。
*/
public final class Message implements Parcelable {
/**
* 用户定义的消息代码,以便接收者能够识别此消息。每个 Handler 都有自己的消息代码命名空间,因此不必担心你的 Handler 与其他 Handler 起冲突。
*/
public int what;
/**
* 如果只需要存储几个整数值,以 arg1 和 arg2 为变量去使用 setData(Bundle) 是较低成本的替代选择方法。
*/
public int arg1;
public int arg2;
/**
* 发送给接收者的任意对象,当使用 Messager 跨进程发送消息时,如果包含着可序列化的框架类时,Message必须是非空的。使用setData()来传输数据。
* 注意,Android 2.2发行版之前不支持此处的Parcelable对象。
*/
public Object obj;
···略···
1.2 MessageQueue 消息队列
定义:用来存储 Message 的数据队列。
官方文档说明:
/**
* 包含着一系列由 Looper 分发的 Message 的一个低级类。
* Message 不是直接添加到 MessageQueue 中的,而是通过与 Looper 关联的 Handler 对象来添加的。
* 你可以使用“loop.myQueue()”方法来获取当前线程的 MessageQueue 对象。
*/
public final class MessageQueue {
private static final String TAG = "MessageQueue";
···略···
}
1.3 Looper 消息循环器
定义:用于为线程执行消息循环的一个类。是 MessageQueue 与 Handler 之间的通讯媒介。
官方文档说明:
/**
* 用于为线程执行消息循环的一个类。
* 线程默认情况下没有与之关联的消息循环;要创建一个,在将要运行循环的线程中调用 Looper.prepare(),然后调用 Looper.loop() 让它处理消息,直到循环停止。
* 与消息循环的大多数交互都是通过 Handler 类进行的。
* 这是一个典型的 Looper 线程实现的例子,使用 Looper.prepare() 和 Looper.loop() 方法创建一个 Handler 对象与 Looper 进行通信。
* <pre>
* class LooperThread extends Thread {
* public Handler mHandler;
*
* public void run() {
* Looper.prepare();
*
* mHandler = new Handler() {
* public void handleMessage(Message msg) {
* // 在这里处理传入的消息
* }
* };
*
* Looper.loop();
* }
* }</pre>
*/
public final class Looper {
/*
* API 实现注意事项:
*
* 该类包含设置和管理基于 MessageQueue 的事件循环所需的代码。
* 影响队列状态的api应该在 MessageQueue 或 Handler 上定义,而不是在 Looper 本身上定义。
* 例如,在队列上定义空闲处理程序和同步屏障,而在 Looper 上定义线程准备、循环和退出。
*/
private static final String TAG = "Looper";
···略···
}
1.4 Message、MessageQueue、Looper之间的关系
一句话概括:
存储在 MessageQueue 中的 Message 被 Looper 循环分发到指定的 Handler 中进行处理。
2. Handler 通信机制原理
关于Handler的通信机制工作原理,请看 Carson_Ho大佬的 Android Handler:图文解析 Handler通信机制 的工作原理 写的超棒,图文解析,一目了然。引用其中一Handler通信流程示意图,如下:
Thread、Handler、Looper三者之间的数量对应关系;
- 一个 Thread 可以有多个 Handler。
- 但一个 Thread 只能由一个 Looper。
- 一个 Handler 只能关联一个 Looper 对象。
- 反之,一个 Looper 可以被多个 Handler 所关联。
3. 源码分析
根据上一篇博客中介绍的Android Handler 使用方法, 我们针对 Handler.sendMessage(msg) 方法展开分析,分为3步:
- 创建 Handler 对象
- 创建 Message 对象
- 分发 Message
3.1 创建 Handler 对象
创建一个 Handler 对象,也就是实例化一个 Handler 对象,在实际的使用中,我也发现有存在三种情况,分别是:
- 在主线程上新建一个 Handler 对象,提供应用程序的 主Looper 对象与之绑定关联。
- 创建一个继承于 Handler类的静态内部类,防止内存泄漏。
- 在子线程上创建 Handler 对象。
我将一一展开分析:
3.1.1 在主线程上新建一个 Handler 对象,提供应用程序的 主Looper 对象与之绑定关联
如下,我们在主线程中新建 Handler 对象,
//在主线程中新建 Handler 对象,并提供应用程序的 主Looper
mHandler = new Handler(Looper.getMainLooper()) {
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
//消息处理
}
};
通过上述代码,我们创建了一个 Handler 对象,并关联应用程序的 主Looper 对象。
这个时候我们看一下 Handler类 的构造函数,如下所示:
/**
* Use the provided {@link Looper} instead of the default one.
* 使用提供的 Looper对象, 而不是使用默认的Looper对象
* @param Looper 不能为 null
*/
public Handler(@NonNull Looper looper) {
this(looper, null, false);
}
可以发现,我们提供给 Handler 的 Looper 是通过 Looper.getMainLooper() 获取的。往下看:
/**
* 返回应用程序的 主Looper, 它存在于应用程序的主线程中。
*/
public static Looper getMainLooper() {
synchronized (Looper.class) {
//返回sMainLooper, 下一步看看sMainLooper是怎么创建 Looper 对象的。
return sMainLooper;
}
}
如上所诉,getMainLooper() 返回 全局变量 sMainLooper 对象,所以我们需要看 sMainLooper 是什么时候被赋值的,如下所示,在 prepareMainLooper() 方法中,sMainLooper 被 myLooper 赋值:
/**
* 将当前线程初始化为 Looper,并将其标记为应用程序的 主Looper
* 应用程序的 主Looper 是由 Android环境 创建的,所以永远不需要自己调用这个函数
*/
public static void prepareMainLooper() {
//调用 prepare() 方法,如果当前线程没有 Looper 对象,就为之新创建一个 Looper 对象。
prepare(false);
synchronized (Looper.class) {
if (sMainLooper != null) {
throw new IllegalStateException("The main Looper has already been prepared.");
}
//返回当前线程所关联的 Looper 对象。
sMainLooper = myLooper();
}
}
上一步 prepareMainLooper 中:调用了 prepare(false) 来创建 Looper 对象,具体如下:
private static void prepare(boolean quitAllowed) {
//sThreadLocal.get() 返回 Looper