
目录:

在分析源码之前,先来了解一下Message、MessageQueue、Looper这几个对象。
定义:是线程间通讯的数据单元,包含着描述信息及任意数据对象,发送到 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;
- ···略···
- 复制代码
定义:用来存储 Message 的数据队列。
官方文档说明:
- /**
- * 包含着一系列由 Looper 分发的 Message 的一个低级类。
- * Message 不是直接添加到 MessageQueue 中的,而是通过与 Looper 关联的 Handler 对象来添加的。
- * 你可以使用“loop.myQueue()”方法来获取当前线程的 MessageQueue 对象。
- */
- public final class MessageQueue {
- private static final String TAG = "MessageQueue";
- ···略···
- }
- 复制代码
定义:用于为线程执行消息循环的一个类。是 MessageQueue 与 Handler 之间的通讯媒介。
官方文档说明:
- /**
- * 用于为线程执行消息循环的一个类。
- * 线程默认情况下没有与之关联的消息循环;要创建一个,在将要运行循环的线程中调用 Looper.prepare(),然后调用 Looper.loop() 让它处理消息,直到循环停止。
- * 与消息循环的大多数交互都是通过 Handler 类进行的。
- * 这是一个典型的 Looper 线程实现的例子,使用 Looper.prepare() 和 Looper.loop() 方法创建一个 Handler 对象与 Looper 进行通信。
- *
- * class LooperThread extends Thread {
- * public Handler mHandler;
- *
- * public void run() {
- * Looper.prepare();
- *
- * mHandler = new Handler() {
- * public void handleMessage(Message msg) {
- * // 在这里处理传入的消息
- * }
- * };
- *
- * Looper.loop();
- * }
- * }
- */
- public final class Looper {
- /*
- * API 实现注意事项:
- *
- * 该类包含设置和管理基于 MessageQueue 的事件循环所需的代码。
- * 影响队列状态的api应该在 MessageQueue 或 Handler 上定义,而不是在 Looper 本身上定义。
- * 例如,在队列上定义空闲处理程序和同步屏障,而在 Looper 上定义线程准备、循环和退出。
- */
- private static final String TAG = "Looper";
- ···略···
- }
- 复制代码
一句话概括: 存储在 MessageQueue 中的 Message 被 Looper 循环分发到指定的 Handler 中进行处理。
关于Handler的通信机制工作原理,请看 Carson_Ho大佬的 Android Handler:图文解析 Handler通信机制 的工作原理 写的超棒,图文解析,一目了然。引用其中一Handler通信流程示意图,如下:

Thread、Handler、Looper三者之间的数量对应关系;
针对 Handler.sendMessage(msg) 方法展开分析,分为3步:
创建一个 Handler 对象,也就是实例化一个 Handler 对象,在实际的使用中,我也发现有存在三种情况,分别是:
我将一一展开分析:
如下,我们在主线程中新建 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 || null,如果返回 Looper 对象,即代表已经为该线程创建了 Looper 对象,
- //从而抛出异常,提示:“每个线程只能创建一个Looper”
- if (sThreadLocal.get() != null) {
- throw new RuntimeException("Only one Looper may be created per thread");
- }
- //否则,调用 new Looper()方法新建一个 Looper 对象,并放入 sThreadLocal 变量中。
- sThreadLocal.set(new Looper(quitAllowed)); //quitAllowed = false
- }
-
- 上一步 prepare() 中:调用了 new Looper() 方法来新创建 Looper 对象,具体如下:
- private Looper(boolean quitAllowed) {
- //新建一个 MessageQueue
- mQueue = new MessageQueue(quitAllowed);
- mThread = Thread.currentThread();
- }
-
-
- 在 prepareMainLooper() 方法中,如果 sMainLooper 为 null,就赋值 sMainLooper = myLooper(); , myLooper() 方法如下:
- /**
- * 返回当前线程所关联的 Looper 对象,如果所调用的线程没有关联的 Looper 对象,就返回 null
- */
- public static @Nullable Looper myLooper() {
- //获取的 Looper 对象,是在 prepare() 方法中通过 sThreadLocal.set(new Looper(quitAllowed)); 所创建的
- return sThreadLocal.get();
- }
- 复制代码
上述代码中,getMainLooper() 方法中的 sMainLooper 是通过 prepareMainLooper() 进行赋值的,具体代码分析如上所述,其流程图如下所示:

上述创建 Handler 对象的方法是 new Handler(Looper.getMainLooper()) ,通过 Looper.getMainLooper() 方法获取 Looper 对象,然后传入到 Handler 的构造函数中,构成绑定关联关系。 但在实际开发中,我们通常将 Handler 写成静态内部类的形式,如下:
- //创建 Handler 对象
- mHandler = new MyHandler(this);
-
- /**
- * 将 Handler 写成静态内部类,防止内存泄露
- */
- public static class MyHandler extends Handler {
- WeakReference<HandlerAddThreadActivity> weakReference;
-
- public MyHandler(HandlerAddThreadActivity activity) {
- weakReference = new WeakReference<>(activity);
- }
-
- @Override
- public void handleMessage(Message msg) {
- super.handleMessage(msg);
- //处理收到的信息
- }
- }
- 复制代码
思考: 疑问?根据上面的代码,我们没有传递 Looper 对象给 Handler 去绑定关联, 那 Handler 为何又能正常工作? 带着疑惑上路:
- 首先看一下 Handler类 的默认构造函数
-
- /**
- * 默认构造函数将这个处理程序与当前线程的{@link Looper}关联起来。
- * 如果此线程没有looper,则此处理程序将无法接收消息,因此将引发异常。
- */
- public Handler() {
- this(null, false);
- }
-
- public Handler(@Nullable Callback callback, boolean async) {
- ···略···
- //返回与当前线程关联的Looper对象。如果调用线程没有关联的 Looper 对象,则返回null
- mLooper = Looper.myLooper();
- //如果 mLooper 为null,则抛出异常。
- if (mLooper == null) {
- throw new RuntimeException(
- "Can't create handler inside thread " + Thread.currentThread()
- + " that has not called Looper.prepare()");
- }
- //获取该 Looper 的 MessageQueue
- mQueue = mLooper.mQueue;
-
- //callback = null && async = false
- mCallback = callback;
- mAsynchronous = async;
- }
-
- 看着不明显,mLooper 是通过 Looper.myLooper() 方法获得的.
- public static @Nullable Looper myLooper() {
- return sThreadLocal.get();
- }
-
- 但这个时候我想起了 prepareMainLooper() 方法。
- /**
- * 将当前线程初始化为 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();
- }
- }
-
- 疑问解除,无论我们有没有手动添加 Looper 给 Handler, Android环境都会为我们自动创建一个主线程的主Looper对象。
- 复制代码
总结: 我们创建的 MyHandler 静态内部类,其实也是在主线程上创建的, Android环境会为我们自动创建一个应用程序的 主Looper 对象,主线程与 主Looper 绑定关联。
ok, 解除了刚刚的疑问,我又问自己,那在子线程创建 Handler 对象呢? 当然,如果你在子线程中新创建一个 Handler 对象,创建的方法为:
- class LooperThread extends Thread {
- public Handler mHandler;
-
- public void run() {
- //为当前线程创建一个 Looper
- Looper.prepare();
-
- //在子线程中创建 Handler 对象
- mHandler = new Handler() {
- public void handleMessage(Message msg) {
- // 在这里处理传入的消息
- }
- };
- //开始消息循环
- Looper.loop();
- }
- }
- 复制代码
在子线程上,我们通过调用 prepare() 来为当前线程创建一个 Looper 对象
- /** 将当前线程初始化为 Looper 对象,在实际开始循环之前创建并引用该 Looper 对象。
- * 请确保在调用此方法后调用 loop() 方法,并通过调用 quit() 结束它
- */
- public static void prepare() {
- prepare(true);
- }
-
- private static void prepare(boolean quitAllowed) {
- if (sThreadLocal.get() != null) {
- throw new RuntimeException("Only one Looper may be created per thread");
- }
- sThreadLocal.set(new Looper(quitAllowed));
- }
- 复制代码
并且在 Handler 与 Looper 构成绑定关联关系后,通过调用 Looper.loop() 方法开始消息循环。
关于创建 Message 对象有两种创建方法,分别是:
- /**
- * 从全局池返回一个新的消息实例。允许我们在许多情况下避免分配新对象。
- */
- public static Message obtain() {
- synchronized (sPoolSync) {
- if (sPool != null) {
- Message m = sPool;
- sPool = m.next;
- m.next = null;
- m.flags = 0; // clear in-use flag
- sPoolSize--;
- return m;
- }
- }
- return new Message();
- }
- 复制代码
本文不过多展示。
在工作线程中通过调用 mHandler.sendMessage(myMessage); 方法来发送消息,这一步是消息入消息队列操作,即将 Message 入 MessageQueue。
- /**
- * 在当前时间之前所有挂起的消息之后, 将消息推到消息队列的末尾。它将该线程所关联的 Handler 的 handleMessage 方法中被接收消息。
- * @return 如果信息成功加入到消息队列中,返回 true,反之,入队列失败则返回 false, 失败的原因通常是因为处理消息队列的“looper”正在退出。
- */
- public final boolean sendMessage(@NonNull Message msg) {
- return sendMessageDelayed(msg, 0);
- }
-
- /**
- * 延时 delayMillis 将消息入消息队列,它将该线程所关联的 Handler 的 handleMessage 方法中被接收消息。
- * @return 如果信息成功加入到消息队列中,返回 true,反之,入队列失败则返回 false, 失败的原因通常是因为处理消息队列的 Looper 正在退出。
- * 注意,true的结果并不意味着将处理该消息——如果 Looper 在消息的交付时间之前退出,则该消息将被删除。
- */
- public final boolean sendMessageDelayed(@NonNull Message msg, long delayMillis) {
- if (delayMillis < 0) {
- //默认 delayMillis = 0
- delayMillis = 0;
- }
- return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis);
- }
-
- /**
- * 在指定时间入队列,深度睡眠的时间会增加额外的执行延迟。它将该线程所关联的 Handler 的 handleMessage 方法中被接收消息。
- * @param uptimeMillis 发送消息的绝对时间,使用{SystemClock # uptimeMillis}获取。
- * @return 如果信息成功加入到消息队列中,返回 true,反之,入队列失败则返回 false, 失败的原因通常是因为处理消息队列的 Looper 正在退出。
- * 注意,true的结果并不意味着将处理该消息——如果 Looper 在消息的交付时间之前退出,则该消息将被删除。
- */
- public boolean sendMessageAtTime(@NonNull Message msg, long uptimeMillis) {
- //获取当前 Looper 对象的消息队列
- MessageQueue queue = mQueue;
- //如果当前 Looper 对象没有消息队列,则抛出异常,返回 false, 代表消息入队列失败
- if (queue == null) {
- RuntimeException e = new RuntimeException(
- this + " sendMessageAtTime() called with no mQueue");
- Log.w("Looper", e.getMessage(), e);
- return false;
- }
- return enqueueMessage(queue, msg, uptimeMillis);
- }
-
- //将消息放入消息队列
- private boolean enqueueMessage(@NonNull MessageQueue queue, @NonNull Message msg,
- long uptimeMillis) {
- msg.target = this;
- msg.workSourceUid = ThreadLocalWorkSource.getUid();
-
- if (mAsynchronous) {
- msg.setAsynchronous(true);
- }
- return queue.enqueueMessage(msg, uptimeMillis);
- }
-
- 根据消息的处理时间入消息队列
- boolean enqueueMessage(Message msg, long when) {
- //获得当前的 Handler 对象,如果为 null, 则抛出异常
- if (msg.target == null) {
- throw new IllegalArgumentException("Message must have a target.");
- }
- //如果消息已经被使用,即已经入队列,则抛出异常
- if (msg.isInUse()) {
- throw new IllegalStateException(msg + " This message is already in use.");
- }
-
- synchronized (this) {
- //如果 Looper 已经退出,抛出异常,入队列失败,返回false
- if (mQuitting) {
- IllegalStateException e = new IllegalStateException(
- msg.target + " sending message to a Handler on a dead thread");
- Log.w(TAG, e.getMessage(), e);
- msg.recycle();
- return false;
- }
-
- msg.markInUse();
- msg.when = when;
- Message p = mMessages;
- boolean needWake;
- //如果队列里没有消息,或者新消息的处理时间排在最前,即作为消息队列新的队头插入消息队列
- if (p == null || when == 0 || when < p.when) {
- //新的队列头部,如果队列是 blocked 的状态则需要唤醒该事件队列。
- msg.next = p;
- mMessages = msg;
- needWake = mBlocked;
- } else {
- //插入处理时间插入到队列的中间。通常我们不需要唤醒事件队列,除非是队列头部的屏障,并且消息是队列中最早的异步消息
- Message prev;
- for (;;) {
- prev = p;
- p = p.next;
- if (p == null || when < p.when) {
- break;
- }
- if (needWake && p.isAsynchronous()) {
- needWake = false;
- }
- }
- msg.next = p; // invariant: p == prev.next
- prev.next = msg;
- }
-
- // We can assume mPtr != 0 because mQuitting is false.
- if (needWake) {
- nativeWake(mPtr);
- }
- }
- return true;
- }
- 复制代码
消息入 MessageQueue 队列后,由 Looper 循环消息队列,然后派发消息,如下所示:
- /**
- * 在线程中运行消息队列,并确保调用 quit() 方法来结束消息循环
- */
- public static void loop() {
- //获取当前线程关联的 Looper 对象,如果该线程没有关联的 Looper 对象,则抛出异常
- final Looper me = myLooper();
- if (me == null) {
- throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");
- }
- //获取该 Looper 对象的消息队列
- final MessageQueue queue = me.mQueue;
-
- //循环消息队列
- for (;;) {
- //取出消息队列中的消息对象,如果消息队列为空,则 block 该线程。
- Message msg = queue.next(); // might block
- if (msg == null) {
- //没有消息则表明消息队列正在退出,解除消息循环
- return;
- }
-
- try {
- //消息对应的 Handler 分发消息
- msg.target.dispatchMessage(msg);
- }
-
- //回收正在使用的消息
- msg.recycleUnchecked();
- }
- }
-
- /**
- * 处理系统消息
- */
- public void dispatchMessage(@NonNull Message msg) {
- if (msg.callback != null) {
- handleCallback(msg);
- } else {
- if (mCallback != null) {
- if (mCallback.handleMessage(msg)) {
- return;
- }
- }
- //如果 Message.callback 为空,执行 handleMessage(msg),即回调复写 handleMessage(msg) 方法。
- handleMessage(msg);
- }
- }
-
- /**
- * 回收可能正在使用的消息,由 MessageQueue 和 Looper 在处理排队消息时在内部使用。
- */
- void recycleUnchecked() {
- //将消息标记为正在使用,同时将其保留在回收的对象池中。并清楚其余所有细节
- flags = FLAG_IN_USE;
- what = 0;
- arg1 = 0;
- arg2 = 0;
- obj = null;
- replyTo = null;
- sendingUid = UID_NONE;
- workSourceUid = UID_NONE;
- when = 0;
- target = null;
- callback = null;
- data = null;
- ···
- }
- 复制代码
Looper 消息循环,发送消息给指定的 Handler中,触发我们覆写的 handleMessage(Message) 方法。