前言
Handler 部分的讲解计划分两篇博客讲完实现原理,一篇主要介绍 Java 层的实现,另一篇介绍 Native 相关的实现,本篇介绍前者。
讲解完实现原理之后,会再新开几篇博客讲解其在系统源码中的主要使用场景等相关内容。
本篇主要内容有:
- MessageQueue 的基本运作流程,包括入队、出队、消息处理等实现原理
- 同步屏障和异步消息
- IdleHandler
- Message池管理
如果这篇文章对你有帮助,请关注点赞加收藏。
还可以关注我的微信公众号“ZZH的Android”,还有更多 Android 系统源码解析的干货文章等着你。
1、Handler 作用
(1) 在线程之间互发消息,实现线程间通信
(2) 发送延时消息,延时执行任务
2、类图
3、Handler-Looper-MessageQueue 模型
整个模型的运行步骤如下:
- 创建 MessageQueue 队列
- 将 Message 对象入队
- 将 Message 对象出队
- 处理出队的 Message
后面跟代码流程时,可以跟着这个图来看,方便理解。
以上运行步骤依赖于 Handler、Looper 和 MessageQueue 三个核心类实现。
4、实现原理
在 Looper.java 文件的开头,给了一段 Looper 使用的示例代码,如下
class LooperThread extends Thread { public Handler mHandler; public void run() { // 创建MessageQueue对象 Looper.prepare(); mHandler = new Handler(Looper.myLooper()) { public void handleMessage(Message msg) { // process incoming messages here } }; // 启动MessageQueue的循环运转 Looper.loop(); } }
其中,Looper.prepare()创建 MessageQueue 对象;
Looper.loop()启动 MessageQueue 队列的循环运转;
Handler 负责发送消息和处理消息。
此处需要注意的是,子线程中并不是必须要创建消息处理机制的这几个对象的,只有当有业务需要才创建即可。
主线程必须创建,而且是由系统在进程启动时创建的,不需要 App 开发者再手动创建。
Looper 给主线程单独定义了专门的方法 prepareMainLooper,代码位置如下:
// frameworks/base/core/java/android/app/ActivityThread.java public static void main(String[] args) { ...... // 创建主线程的MessageQueue Looper.prepareMainLooper(); ...... ActivityThread thread = new ActivityThread(); thread.attach(false, startSeq); if (sMainThreadHandler == null) { sMainThreadHandler = thread.getHandler(); } if (false) { Looper.myLooper().setMessageLogging(new LogPrinter(Log.DEBUG, "ActivityThread")); } // End of event ActivityThreadMain. Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER); // 启动MessageQueue循环运转 Looper.loop(); throw new RuntimeException("Main thread loop unexpectedly exited"); }
4.1 Looper.prepare()->MessageQueue 的创建
当 Looper 执行其 prepare()函数时会创建 MessageQueue 对象。MessageQueue 是一个包含 Message 元素的队列,
从其名字翻译为队列,实际上是一个单向链表,因为每个 Message 对象中的 next 成员会指向下一个 Message 对象。
创建 MessageQueue 代码的如下:
// frameworks/base/core/java/android/os/Looper.java public static void prepare() { // 这里的true表示MessageQueue队列可以手动停止运转。 // 调用Looper的quit方法可以停止运转。 prepare(true); } // 注意这个函数是private方法,App无法使用。说明子线程的 // quitAllowed一定为true。 // 这里使用了ThreadLocal,表明每个线程都有专属的一个唯一的Looper对象 private static void prepare(boolean quitAllowed) { // 如果重复执行prepare方法,就会提示错误。 // 说明每个线程只能创建一个Looper对象 if (sThreadLocal.get() != null) { throw new RuntimeException("Only one Looper may be created per thread"); } // 创建Looper对象,并保存到sThreadLocal里, // 这里quitAllowed=true。 sThreadLocal.set(new Looper(quitAllowed)); }
可以通过 Looper 的 myLooper()函数获取当前线程的 Looper 对象:
public static @Nullable Looper myLooper() { return sThreadLocal.get(); }
再看下给主线程使用的 prepareMainLooper 函数:
// 这个方法不允许应用再调用 public static void prepareMainLooper() { // 这里传入了false,说明主线程的消息循环不允许被停止。 // 原因是主线程中有很多核心的功能是由Handler实现的, // 比如Activity生命周期的回调。 prepare(false); synchronized (Looper.class) { if (sMainLooper != null) { throw new IllegalStateException("The main Looper has already been prepared."); } // 主线程的Looper对象也会保存在sMainLooper中, // 这样的获取,获取主线程的Looper对象就不用再从 // sThreadLocal 中拿了,可以节省时间,提高性能。 // 当需要创建基于主线程的Handler对象时,可以直接 // 使用Looper的getMainLooper方法获取主线程Looper对象。 sMainLooper = myLooper(); } }
Looper 的构造函数
// 创建MessageQueue对象,保存在mQueue变量中; // 并且将当前线程保存在mThread变量中。 // 这里可以看到quitAllowed最终传递给了MessageQueue private Looper(boolean quitAllowed) { mQueue = new MessageQueue(quitAllowed); mThread = Thread.currentThread(); }
下面看下 MessageQueue 的构造函数
// frameworks/base/core/java/android/os/MessageQueue.java MessageQueue(boolean quitAllowed) { // 是否可以被手动停止 // 主线程必须为false // 子线程默认为true,也只能为true mQuitAllowed = quitAllowed; // 创建NativeMessageQueue对象,并保存其引用。 mPtr = nativeInit(); }
下面看下 nativeInit()的实现。
// frameworks/base/core/jni/android_os_MessageQueue.cpp // 可以看到nativeInit()对应实现为android_os_MessageQueue_nativeInit static const JNINativeMethod gMessageQueueMethods[] = { /* name, signature, funcPtr */ { "nativeInit", "()J", (void*)android_os_MessageQueue_nativeInit }, ...... }; // 看下android_os_MessageQueue_nativeInit实现 static jlong android_os_MessageQueue_nativeInit(JNIEnv* env, jclass clazz) { // 创建NativeMessageQueue对象 NativeMessageQueue* nativeMessageQueue = new NativeMessageQueue(); if (!nativeMessageQueue) { jniThrowRuntimeException(env, "Unable to allocate native queue"); return 0; } // 增加强引用计数,确保该对象不会被释放 nativeMessageQueue->incStrong(env); // 将nativeMessageQueue的指针返回到java层。 return reinterpret_cast<jlong>(nativeMessageQueue); } // 下面再看下NativeMessageQueue的构造函数, // 创建了Native的Looper对象。 // Native Handler相关的另起一篇文章单独介绍 NativeMessageQueue::NativeMessageQueue() : mPollEnv(NULL), mPollObj(NULL), mExceptionObj(NULL) { mLooper = Looper::getForThread(); if (mLooper == NULL) { mLooper = new Looper(false); Looper::setForThread(mLooper); } }
再看下 Looper.quit 方法,这个方法是用来结束消息队列处理流程的。
可以看到有两个方法,最终都调用了 mQueue.quit,传递的参数不同而已。
public void quit() { mQueue.quit(false); } public void quitSafely() { mQueue.quit(true); }
MessageQueue 的 quit
void quit(boolean safe) { if (!mQuitAllowed) { throw new IllegalStateException("Main thread not allowed to quit."); } synchronized (this) { if (mQuitting) { return; } // 将mQuitting为true,这个变量在MessageQueue循环处理消息时 // 会做判断,如果是true,则停止 循环处理。 mQuitting = true; // 参数的不同,会分别调用下面的两个方法。 // 这两个方法涉及到队列的操作,后面我们讲完入队和出队后 // 再分析下面两个函数的实现。 if (safe) { removeAllFutureMessagesLocked(); } else { removeAllMessagesLocked(); } // We can assume mPtr != 0 because mQuitting was previously false. // 唤醒线程,这样就可以循环起来然后拿到mQuitting做判断退出。 nativeWake(mPtr); } }
小结
- Looper 的静态方法 prepare 函数里面创建了 Looper 对象,并且将 Looper 对象保存在了 sThreadLocal 中,这样可以保证每个线程都有一个自己的 Looper 对象。
- 主线程有特殊的创建 Looper 对象的方法 prepareMainLooper,并且创建完成后除了保存在 sThreadLocal 中外,还保存在了一个静态变量 sMainLooper 中。
- Looper 有个 MessageQueue 类型成员 mQueue,在 Looper 的构造函数中进行创建,最终创建了一个 Native 对象 NativeMessageQueue,并且 java 层拿到了它的指针。
- Looper 的 quit 和 quitSafely 方法可以停止消息循环,其最终调用的都是 MessageQueue 的 quit 方法。
- MessageQueue 有个成员 mQuitAllowed,由 Looper 的私有方法 prepare 传入,表示消息循环是否可以通过调用 quit 被停止。子线程可以被停止,主线程不能被停止。
可以推测出的结论
- 每个线程最多只有一个 Looper 对象和一个 MessageQueue 对象。
上面讲完 MessageQueue 队列的创建,下面开始讲入队和出队。
4.2 MessageQueue 入队操作
入队操作由 Handler 完成。
4.2.1 Handler 的创建
// frameworks/base/core/java/android/os/Handler.java /** * Default constructor associates this handler with the {@link Looper} for the * current thread. * * If this thread does not have a looper, this handler won't be able to receive messages * so an exception is thrown. * * @deprecated Implicitly choosing a Looper during Handler construction can lead to bugs * where operations are silently lost (if the Handler is not expecting new tasks and quits), * crashes (if a handler is sometimes created on a thread without a Looper active), or race * conditions, where the thread a handler is associated with is not what the author * anticipated. Instead, use an {@link java.util.concurrent.Executor} or specify the Looper * explicitly, using {@link Looper#getMainLooper}, {link android.view.View#getHandler}, or * similar. If the implicit thread local behavior is required for compatibility, use * {@code new Handler(Looper.myLooper())} to make it clear to readers. * */ @Deprecated public Handler() { this(null, false); }
以上不带参数的默认构造函数已经被弃用,注释里写了一堆原因,总结就是这么用会带来很多问题。如果要用,就显式指定其依赖的 Looper 对象。
/** * Use the provided {@link Looper} instead of the default one. * * @param looper The looper, must not be null. */ public Handler(@NonNull Looper looper) { this(looper, null, false); } /** * Use the provided {@link Looper} instead of the default one and take a callback * interface in which to handle messages. * * @param looper The looper, must not be null. * @param callback The callback interface in which to handle messages, or null. */ public Handler(@NonNull Looper looper, @Nullable Callback callback) { this(looper, callback, false); }
上面两个构造函数最终都会到下面的 hide 方法。
/** * @hide */ @UnsupportedAppUsage public Handler(@NonNull Looper looper, @Nullable Callback callback, boolean async) { // 下面三个主要变量赋值,比较好理解 mLooper = looper; mQueue = looper.mQueue; mCallback = callback; //是否为异步消息 mAsynchronous = async; }
- 第一个 Looper 参数是 NonNull,通过 Looper.myLooper()方法获取,如果没有调用过 Looper 的 prepare 方法,则会报错。
- 第二个参数 Callback 是 Handler 的内部接口,如果传入了这个参数不是空,则消息出队后将不会执行 Handler 的 handleMessage 方法,而是会执行实现了 Callback 接口对象的 handleMessage 方法。这样的话就不需要重写 Handler 的 handleMessage 了。
/** * Callback interface you can use when instantiating a Handler to avoid * having to implement your own subclass of Handler. */ public interface Callback { /** * @param msg A {@link android.os.Message Message} object * @return True if no further handling is desired */ boolean handleMessage(@NonNull Message msg); }
- 第三个参数表示,由这个 Handler 发送的消息是否为异步消息。
异步消息
上面 Handler 的构造函数中,其中最后一个参数需要特别注意一下。
它表示由这个 Handler 发送的 Message 消息是否为异步消息。
如果参数是 false,则表示此 Handler 发送的消息都是同步消息;如果参数是 true,则表示此 Handler 发送的消息都是异步消息。
从上面 Handler 的构造函数可以看出,普通应用的话这个参数默认为 false,也就是只能创建同步消息。
对于系统进程,则可以直接调用,指定 Handler 发送的消息是同步还是异步消息。
这里第一次出现异步消息这个概念,我们现在先理解为异步消息会比同步消息优先执行。
普通应用如何创建异步消息的 Handler
那么普通应用有办法创建异步消息的 Handler 吗?答案是有。
Handler 提供了两个静态方法,如下:
可以看到其最后一个参数为 true,表示异步。
@NonNull public static Handler createAsync(@NonNull Looper looper) { if (looper == null) throw new NullPointerException("looper must not be null"); return new Handler(looper, null, true); } @NonNull public static Handler createAsync(@NonNull Looper looper, @NonNull Callback callback) { if (looper == null) throw new NullPointerException("looper must not be null"); if (callback == null) throw new NullPointerException("callback must not be null"); return new Handler(looper, callback, true); }
关于异步消息我们先讲这么多,后面在用到的时候会继续讲解。
4.2.2 Handler 发送 Message 入队
Handler 有一系列的 postXXX 和 sendXXX 函数,最终都会调用到 sendMessageAtTime 函数。
不同的方法给下面的函数的两个参数赋值不同而已。
uptimeMillis:表示消息的延时时间,如果函数不带 Delay 或者要插入队头的则赋值为 0;
msg: Message 对象,调用不同的 post 或者 send 方法,对其不同成员进行赋值。
public boolean sendMessageAtTime(@NonNull Message msg, long uptimeMillis) { // mQueue是构造Handler时由传入的Looper对象提供。 MessageQueue queue = mQueue; // 如果没有MessageQueue对象,直接报异常退出。 if (queue == null) { RuntimeException e = new RuntimeException( this + " sendMessageAtTime() called with no mQueue"); Log.w("Looper", e.getMessage(), e); return false; } // 继续执行Message入队操作 return enqueueMessage(queue, msg, uptimeMillis); } private boolean enqueueMessage(@NonNull MessageQueue queue, @NonNull Message msg, long uptimeMillis) { // Message类中有个target成员,其类型为Handler, // 这里将其赋值为当前Handler对象,后续消息出队后 // 可能交给Handler处理消息。 msg.target = this; msg.workSourceUid = ThreadLocalWorkSource.getUid(); // 是否为异步消息,这里可以看到,如果构造Handler时mAsynchronous为true, // 则将Message设置为异步标志。这样的话使用这个Handler发送的Message将 // 都是异步Message。 if (mAsynchronous) { msg.setAsynchronous(true); } // 调用MessageQueue的enqueueMessage方法入队 return queue.enqueueMessage(msg, uptimeMillis); }
上面使用到了 Message 的 setAsynchronous 方法,我们看下其实现:
// frameworks/base/core/java/android/os/Message.java public void setAsynchronous(boolean async) { if (async) { flags |= FLAG_ASYNCHRONOUS; } else { flags &= ~FLAG_ASYNCHRONOUS; } }
同时 Message 还提供了一个判断自己是否为异步消息点方法:
// frameworks/base/core/java/android/os/Message.java public boolean isAsynchronous() { return (flags & FLAG_ASYNCHRONOUS) != 0; }
FLAG_ASYNCHRONOUS 的值:
// frameworks/base/core/java/android/os/Message.java static final int FLAG_ASYNCHRONOUS = 1 << 1;
消息入队
这里要敲黑板了,第一个重点部分来了。
MessageQueue 的入队操作,其实就是按照 Message 的延时执行时间参数 when 来进行排序入队。
// frameworks/base/core/java/android/os/MessageQueue.java boolean enqueueMessage(Message msg, long when) { // 通过Handler进行入队的话这个参数是不会为空的。 // 这里要注意一下,并不是所有的在队列中的msg的target // 都不是null,有一类Message叫做同步屏障,它的target就必须为null, // 只不过它不是通过这个方法进行入队的。所以后面我们看到代码还有 // msg.target == null的判断时不要惊讶。至于什么是同步屏障, // 后面会讲到的。 if (msg.target == null) { throw new IllegalArgumentException("Message must have a target."); } // 入队一个Message时加锁 synchronized (this) { if (msg.isInUse()) { throw new IllegalStateException(msg + " This message is already in use."); } // 如果此时调用了Looper的quit函数,则说明取消了MessageQueue队列的运转,直接退出。 // 这里说明,当quit后,将不能再入队新的Message。 if (mQuitting) { IllegalStateException e = new IllegalStateException( msg.target + " sending message to a Handler on a dead thread"); Log.w(TAG, e.getMessage(), e); // 释放msg msg.recycle(); return false; } // 标记为正在使用状态 msg.markInUse(); // when就是此msg延时多久执行 msg.when = when; // mMessage初始为空,表示的是队列的队头 Message p = mMessages; // 当消息入队但是还未到其执行时间时,线程会进入阻塞, // 这里的needWake用来判断是否需要唤醒线程进行出队 boolean needWake; // 这里的三个条件满足其一都会将当前Message插入队头 // p == null,说明当前队列为空,新来的Message自然作为队头 // when = 0,说明此Message没有延时需要立即执行,所以也放在队头 // when < p.when,说明当前Message的延时小于队头Message的延时,所以放在队头 if (p == null || when == 0 || when < p.when) { // New head, wake up the event queue if blocked. msg.next = p; mMessages = msg; // 这里的mBlocked表示MessageQueue的出队函数next()是否阻塞。 // 如果是阻塞状态,则队头Message变化时要将其唤醒,表明这个时候 // 可能有消息需要出队处理了,特别是当when == 0 的时候。 needWake = mBlocked; } else { // Inserted within the middle of the queue. Usually we don't have to wake // up the event queue unless there is a barrier at the head of the queue // and the message is the earliest asynchronous message in the queue. // 这里的p实际上是队头的Message,但是这里对其target == null做了判断, // 但是该函数的开头却有target == null的话会直接抛异常退出,那么这里会是null吗? // 除非有一种可能,那就是这个target为null的Message不是通过本方法入队的。 // 这里又引入了一个新的概念:同步屏障(synchronization barriers), // 同步屏障我们先理解为一个target为null的Message,下面会详细介绍。 // 如果队头是一个同步屏障且当前入队的消息是异步消息,且mBlocked为true,则 // 需要唤醒当前线程来。 needWake = mBlocked && p.target == null && msg.isAsynchronous(); // 下面的操作是真正入队的操作,从队头开始遍历 Message prev; for (;;) { prev = p; p = p.next; // p == null 表示遍历到了队尾 // when < p.when 表示队列按延时时间排序 // 延时时间越小的越靠前,越靠近队头 if (p == null || when < p.when) { break; } // 如果队列中有异步消息,则将needWake置为false。 // if (needWake && p.isAsynchronous()) { needWake = false; } } // 将当前msg插入队列,插入p的前面 msg.next = p; // invariant: p == prev.next prev.next = msg; } // We can assume mPtr != 0 because mQuitting is false. // 如果needWake为true,则唤醒线程 if (needWake) { nativeWake(mPtr); } } return true; }
同步屏障
上面我们又遇见了一个新的概念:同步屏障,或者叫做同步屏障机制。在这个机制中,包含一个 target 为 null 的 Message,这个 Message 并不是通过上面的 enqueueMessage 方法入队的,而是另有他法。
插入同步屏障 Message 的方法 MessageQueue 的 postSyncBarrier
// frameworks/base/core/java/android/os/MessageQueue.java /** * Posts a synchronization barrier to the Looper's message queue. * @hide */ @UnsupportedAppUsage @TestApi public int postSyncBarrier() { return postSyncBarrier(SystemClock.uptimeMillis()); } private int postSyncBarrier(long when) { // Enqueue a new sync barrier token. // We don't need to wake the queue because the purpose of a barrier is to stall it. synchronized (this) { // mNextBarrierToken 表示每个同步屏障Message的token, // 初始值为0,从1开始记录 final int token = mNextBarrierToken++; // 这里队Message赋值,可以看到并没有给target赋值,所以msg.targt=null final Message msg = Message.obtain(); msg.markInUse(); msg.when = when; msg.arg1 = token; // 将同步屏障msg入队,这里按照when的大小排序入队 Message prev = null; Message p = mMessages; if (when != 0) { while (p != null && p.when <= when) { prev = p; p = p.next; } } if (prev != null) { // invariant: p == prev.next // 将msg插到p的前面 msg.next = p; prev.next = msg; } else { // msg插入队头的情况 msg.next = p; mMessages = msg; } // 返回值为msg的token return token; } }
移除同步屏障 Message 的方法 removeSyncBarrier(int token),
参数为 postSyncBarrier 时返回的 token 值。
/** * Removes a synchronization barrier. * * @param token The synchronization barrier token that was returned by * {@link #postSyncBarrier}. * * @throws IllegalStateException if the barrier was not found. * * @hide */ @UnsupportedAppUsage @TestApi public void removeSyncBarrier(int token) { // Remove a sync barrier token from the queue. // If the queue is no longer stalled by a barrier then wake it. synchronized (this) { Message prev = null; Message p = mMessages; while (p != null && (p.target != null || p.arg1 != token)) { prev = p; p = p.next; } // 如果p为空,说明没找到需要移除的同步屏障Message if (p == null) { throw new IllegalStateException("The specified message queue synchronization " + " barrier token has not been posted or has already been removed."); } // 如果p != null,则说明p就是需要移除的msg final boolean needWake; if (prev != null) { // 要移除的msg不是队头 prev.next = p.next; needWake = false; } else { // 要移除的msg是队头 mMessages = p.next; // 队头发生变更,且队头是同步消息,needWake为true needWake = mMessages == null || mMessages.target != null; } // 释放移除掉的Message p p.recycleUnchecked(); // If the loop is quitting then it is already awake. // We can assume mPtr != 0 when mQuitting is false. if (needWake && !mQuitting) { nativeWake(mPtr); } } }
到目前为止,我们已经接触并分别简单介绍了同步屏障和异步消息两个概念了。
他们是两个 Message 对象,同步屏障的特点是 msg.target=null,异步消息的特点是 isAsynchronous 为 true。
那么这两者的作用究竟是什么呢?其实他们两个是一起发生作用的,或者说,同步屏障的作用是为了保证异步消息可以优先执行。当出队遇到队头为同步屏障时,则其后面的同步消息将不会被执行,只会执行异步消息,除非将同步屏障移除。
需要说明的是,添加和移除同步屏障是 hide 方法,只能系统进程使用。
下面的出队操作将会看到同步屏障和异步消息的处理逻辑和其作用。
4.3 MessageQueue 的流转-出队
4.3.1 Looper.loop()
Looper.loop()方法执行后消息队列开始运转,按规则进行出队操作。
/** * Run the message queue in this thread. Be sure to call * {@link #quit()} to end the loop. */ @SuppressWarnings("AndroidFrameworkBinderIdentity") public static void loop() { // 对Looper进行检查 final Looper me = myLooper(); if (me == null) { throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread."); } if (me.mInLoop) { Slog.w(TAG, "Loop again would have the queued messages be executed" + " before this one completed."); } // loop开始后设置mInLoop为true me.mInLoop = true; // Make sure the identity of this thread is that of the local process, // and keep track of what that identity token actually is. Binder.clearCallingIdentity(); final long ident = Binder.clearCallingIdentity(); // Allow overriding a threshold with a system prop. e.g. // adb shell 'setprop log.looper.1000.main.slow 1 && stop && start' // 这里可以通过属性设置一个消息处理时间的阈值,如果消息处理超过这个时间,将会 // 有警告级别日志打印,默认这个属性是没有的,调试的时候可以自己设置这个属性来 // 测试消息处理时间。 // Looper是有专门的接口设置这个时间阈值的,如果同时设置了这个属性值,那么Looper接口 // 设置的值会被这个属性值覆盖,后面代码可以看到。 final int thresholdOverride = SystemProperties.getInt("log.looper." + Process.myUid() + "." + Thread.currentThread().getName() + ".slow", 0); // 这个值默认为false,表示msg的投递时间未超过设置的阈值 me.mSlowDeliveryDetected = false; // 这里进入了for循环,如果loopOnce返回false,则会退出循环, // 也就表示MessageQueue不工作了,除非再次调用loop方法, // 当调用quit方法后,loopOnce将会返回false for (;;) { if (!loopOnce(me, ident, thresholdOverride)) { return; } } }
下面看下 loopOnce 方法的实现
/** * Poll and deliver single message, return true if the outer loop should continue. */ @SuppressWarnings("AndroidFrameworkBinderIdentity") private static boolean loopOnce(final Looper me, final long ident, final int thresholdOverride) { // 执行MessageQueue的next()函数,返回下一个将要处理的Message, // 如果下一个Message时间未到,next()方法则会阻塞等待。 // 这个函数下面会详细分析。 Message msg = me.mQueue.next(); // might block // 如果调用了Looper的quit方法,那么next()函数将会返回null。 if (msg == null) { // No message indicates that the message queue is quitting. return false; } // This must be in a local variable, in case a UI event sets the logger // 这里是打印Message的处理日志的,这里的mLogging可以通过Looper的 // setMessageLogging方法设置,默认为null。 final Printer logging = me.mLogging; if (logging != null) { logging.println(">>>>> Dispatching to " + msg.target + " " + msg.callback + ": " + msg.what); } // Make sure the observer won't change while processing a transaction. // sObserver可以通过Looper的setObserver方法设置,是用来监听回调 // Message的处理状态的。 final Observer observer = sObserver; // Looper的setTraceTag方法可以设置mTraceTag // 用来记录trace信息。此方法为hide方法,普通应用无法使用。 final long traceTag = me.mTraceTag; // Looper的setSlowLogThresholdMs方法用来设置这两个值,也是hide方法。 // 到这里需要解释一下这两个值的含义了。 // mSlowDispatchThresholdMs: 消息时间的阈值,或者理解为处理完一个消息的时间阈值。 // 如果消息处理时间比这个大,说明消息处理的比预期慢了,可能发生了异常。 // mSlowDeliveryThresholdMs: 表示消息投递的时间差阈值,比如我的Message是延时500毫秒 // 执行的,实际开始处理的时间(后面的dispatchStart)是550毫秒后,这就差了50毫秒,如果我们 // 设置的阈值小于50,就说明消息投递的时间误差超出预期,可能发生异常。 long slowDispatchThresholdMs = me.mSlowDispatchThresholdMs; long slowDeliveryThresholdMs = me.mSlowDeliveryThresholdMs; // thresholdOverride前面我们讲过,是调试时需要手动设置的属性值。 // 如果这个值大于0,则覆盖setSlowLogThresholdMs方法设置的两个值。 if (thresholdOverride > 0) { slowDispatchThresholdMs = thresholdOverride; slowDeliveryThresholdMs = thresholdOverride; } // 是否打印警告日志的开关 final boolean logSlowDelivery = (slowDeliveryThresholdMs > 0) && (msg.when > 0); final boolean logSlowDispatch = (slowDispatchThresholdMs > 0); final boolean needStartTime = logSlowDelivery || logSlowDispatch; final boolean needEndTime = logSlowDispatch; // 记录开始处理msg的trace if (traceTag != 0 && Trace.isTagEnabled(traceTag)) { Trace.traceBegin(traceTag, msg.target.getTraceName(msg)); } // 记录消息派发的开始时间 final long dispatchStart = needStartTime ? SystemClock.uptimeMillis() : 0; final long dispatchEnd; Object token = null; if (observer != null) { // observer回调开始派发消息 token = observer.messageDispatchStarting(); } long origWorkSource = ThreadLocalWorkSource.setUid(msg.workSourceUid); try { // 执行Handler的dispatchMessage函数 msg.target.dispatchMessage(msg); if (observer != null) { // observer回调派发消息结束 observer.messageDispatched(token, msg); } // 记录消息派发的结束时间 dispatchEnd = needEndTime ? SystemClock.uptimeMillis() : 0; } catch (Exception exception) { if (observer != null) { // observer回调派发消息发生异常 observer.dispatchingThrewException(token, msg, exception); } throw exception; } finally { ThreadLocalWorkSource.restore(origWorkSource); if (traceTag != 0) { // 记录处理完成msg的trace Trace.traceEnd(traceTag); } } if (logSlowDelivery) { // 前面说过,mSlowDeliveryDetected初始化为false if (me.mSlowDeliveryDetected) { if ((dispatchStart - msg.when) <= 10) { Slog.w(TAG, "Drained"); me.mSlowDeliveryDetected = false; } } else { // showSlowLog函数用来计算dispatchStart-msg.when是否大于slowDeliveryThresholdMs, // 如果是,则打印警告日志。 if (showSlowLog(slowDeliveryThresholdMs, msg.when, dispatchStart, "delivery", msg)) { // Once we write a slow delivery log, suppress until the queue drains. // 并且将mSlowDeliveryDetected赋值true,用来表示队列中有一个消息投递的慢了, // 直到遇见下一个投递时间差没有超出10毫秒,再将其赋值false,也就是上面的if条件语句。 me.mSlowDeliveryDetected = true; } } } if (logSlowDispatch) { // 如果消息派发处理时间超出阈值,打印警告日志。 showSlowLog(slowDispatchThresholdMs, dispatchStart, dispatchEnd, "dispatch", msg); } // 如果我们设置了Printf,则打印处理完毕的日志 if (logging != null) { logging.println("<<<<< Finished to " + msg.target + " " + msg.callback); } // Make sure that during the course of dispatching the // identity of the thread wasn't corrupted. final long newIdent = Binder.clearCallingIdentity(); if (ident != newIdent) { Log.wtf(TAG, "Thread identity changed from 0x" + Long.toHexString(ident) + " to 0x" + Long.toHexString(newIdent) + " while dispatching to " + msg.target.getClass().getName() + " " + msg.callback + " what=" + msg.what); } // 对已经处理完的消息对象进行回收 msg.recycleUnchecked(); return true; }
上面有两个方法我们没有展开将,一个是 MessageQueue 的 next()方法,一个是 Handler 的 dispatchMessage 方法,下面开始讲解。
4.3.2 MessageQueue 的 next()
需要注意的是,此时的 MessageQueue 里面的 Message 已经按照其延时时间 when 从小到大排序完成,when 越小越靠前靠近队头。
Message next() { // Return here if the message loop has already quit and been disposed. // This can happen if the application tries to restart a looper after quit // which is not supported. // 调用quit方法后,mPtr会赋值0,这里就会返回null,结束队列的循环运转。 final long ptr = mPtr; if (ptr == 0) { return null; } // 这里又出现一个新名词,IdleHandler // 后面会详细解释 int pendingIdleHandlerCount = -1; // -1 only during first iteration // 下一个消息执行还需要等待的时间 int nextPollTimeoutMillis = 0; // 使用一个for循环寻找下一个要执行的Message, // 找到后将Message返回。 for (;;) { if (nextPollTimeoutMillis != 0) { Binder.flushPendingCommands(); } // 这里是线程阻塞时间 nativePollOnce(ptr, nextPollTimeoutMillis); synchronized (this) { // Try to retrieve the next message. Return if found. // 获取当前时间 final long now = SystemClock.uptimeMillis(); Message prevMsg = null; Message msg = mMessages; // 如果遇到同步屏障,则其后面的同步消息将都会略过不执行, // 只执行异步消息,除非调用removeSyncBarrier移除同步屏障, // 这种情况只有当同步屏障成为队头时,也就是如果同步屏障前面有 // 同步消息,则会先执行前面的同步消息。 if (msg != null && msg.target == null) { // Stalled by a barrier. Find the next asynchronous message in the queue. do { prevMsg = msg; msg = msg.next; } while (msg != null && !msg.isAsynchronous()); } // 找到了要执行的msg if (msg != null) { // 如果当前时间now还小于msg的执行时间,则计算下还需要等待的时间 if (now < msg.when) { // Next message is not ready. Set a timeout to wake up when it is ready. nextPollTimeoutMillis = (int) Math.min(msg.when - now, Integer.MAX_VALUE); } else { // Got a message. // 否则msg已经到了可以执行的时间,需要返回 // 同时mBlocked置为false mBlocked = false; if (prevMsg != null) { // 走到这里说明找到的是异步msg // 从队列中移除找到的msg prevMsg.next = msg.next; } else { // 走到这里说明找到的msg是队头, // 将msg的下一个元素置为新的队头。 mMessages = msg.next; } // 这里将msg标志为正在使用,然后返回。 msg.next = null; if (DEBUG) Log.v(TAG, "Returning message: " + msg); msg.markInUse(); return msg; } } else { // 如果msg为null,说明队列中没有要执行的消息了, // 或者此时表头为同步屏障,但是队列中没有异步消息 // No more messages. // 阻塞,直到下个Message入队 nextPollTimeoutMillis = -1; } // 如果在运行过程中,有地方调用了Looper的quit方法,则退出loop循环操作。 // 此后所有的msg都将不会执行,除非再次调用Looper.loop()启动运行 // Process the quit message now that all pending messages have been handled. if (mQuitting) { // dispose函数用于释放 dispose(); return null; } // If first time idle, then get the number of idlers to run. // Idle handles only run if the queue is empty or if the first message // in the queue (possibly a barrier) is due to be handled in the future. // 从这里开始都next()函数结束,剩下的代码都是IdleHandler相关的了。 // 请注意,这里的代码还在上面的for循环里,for循环开始前pendingIdleHandlerCount赋值了-1。 // 所以,第一次for循环 或者 队头msg为空(mMessages == null) // 或者队头的msg还未到执行时间(now < mMessages.when), // 就以mIdleHandlers的size重新赋值pendingIdleHandlerCount。 // 其中mIdleHandlers是IdleHandler的一个列表,初始为空。 // IdleHandler是一个接口类型,其有一个方法boolean queueIdle(). // 列表mIdleHandlers需要通过MessageQueue的addIdleHandler方法添加元素, // 通过MessageQueue的removeIdleHandler方法删除元素。 // IdleHandler存在的意义是当MessageQueue空闲时可以执行一些额外的任务。 if (pendingIdleHandlerCount < 0 && (mMessages == null || now < mMessages.when)) { pendingIdleHandlerCount = mIdleHandlers.size(); } // 如果pendingIdleHandlerCount<=0,说明没有需要执行的IdleHandler if (pendingIdleHandlerCount <= 0) { // No idle handlers to run. Loop and wait some more. mBlocked = true; continue; } // mPendingIdleHandler是IdleHandler类型的数组,其最小长度为4。 if (mPendingIdleHandlers == null) { mPendingIdleHandlers = new IdleHandler[Math.max(pendingIdleHandlerCount, 4)]; } // 将mPendingIdleHandlers中的元素赋值到mPendingIdleHandlers数组中 mPendingIdleHandlers = mIdleHandlers.toArray(mPendingIdleHandlers); } // Run the idle handlers. // We only ever reach this code block during the first iteration. // 遍历mPendingIdleHandlers数组,执行其queueIdle()函数。 for (int i = 0; i < pendingIdleHandlerCount; i++) { final IdleHandler idler = mPendingIdleHandlers[i]; mPendingIdleHandlers[i] = null; // release the reference to the handler boolean keep = false; try { keep = idler.queueIdle(); } catch (Throwable t) { Log.wtf(TAG, "IdleHandler threw exception", t); } // 如果queueIdle()函数返回false,则将其IdleHandler从列表中移除。 // 这样下次执行next()时,将不会再执行这个IdleHandler的queueIdle()方法 // 否则若queueIdle()函数返回true,则下次next()时就还会执行其 // queueIdle()函数。 if (!keep) { synchronized (this) { mIdleHandlers.remove(idler); } } } // 到这里,如果有IdleHandler的话,则已经执行完一轮。 // 此时需要重置pendingIdleHandlerCount = 0 // 这样下次for循环时,就不会再执行其queueIdle函数了。 // 下次执行要在下一次next()函数执行时继续按照上面的规则判定是否执行。 // Reset the idle handler count to 0 so we do not run them again. pendingIdleHandlerCount = 0; // While calling an idle handler, a new message could have been delivered // so go back and look again for a pending message without waiting. // 走到这里说明队列空闲时执行了额外的IdleHandler任务,此时可能已经到了下一个Message需要 // 执行的时间,所以将休眠唤醒时间赋值为0,也就是下次for循环时直接唤醒线程。 nextPollTimeoutMillis = 0; } }
4.3.3 Handler 的 dispatchMessage
dispatchMessage 是 Message 出队后的最后一步,进行消息处理。
public void dispatchMessage(@NonNull Message msg) { // 如果是通过post Runnable发送的消息,则会回调Runnable的run方法 if (msg.callback != null) { handleCallback(msg); } else { // 如果构造Handler时传入了Callback参数,则回调 // Callback的handleMessage方法 if (mCallback != null) { if (mCallback.handleMessage(msg)) { return; } } //如果以上callback都没有,最后才是执行Handler的 // handleMessage方法 handleMessage(msg); } }
5、Looper quit
最后分析一下 quit 方法的实现,前面讲过,quit 有两个方法,分别是 quit() 和 quitSafely(),其最终会调用到 MessageQueue 的 quit 方法中
void quit(boolean safe) { if (!mQuitAllowed) { throw new IllegalStateException("Main thread not allowed to quit."); } synchronized (this) { if (mQuitting) { return; } mQuitting = true; if (safe) { removeAllFutureMessagesLocked(); } else { removeAllMessagesLocked(); } // We can assume mPtr != 0 because mQuitting was previously false. nativeWake(mPtr); } }
5.1 removeAllMessagesLocked
这个比较简单,遍历队列,对每个 Message 进行回收,最后将队头 mMessages 赋值为 null。
private void removeAllMessagesLocked() { Message p = mMessages; while (p != null) { Message n = p.next; p.recycleUnchecked(); p = n; } mMessages = null; }
5.2 removeAllFutureMessagesLocked
这个函数相比 removeAllMessagesLocked 多了一个 Future 字段,字面意思是未来,我们猜测这个函数移除的是还未到执行时间的 Message,如果 Message 已经到了执行时间,在投递阶段,还未派发完成,则需要执行完成。
下面看下实现跟我们猜测是否一样。
private void removeAllFutureMessagesLocked() { final long now = SystemClock.uptimeMillis(); Message p = mMessages; if (p != null) { // 队头还未到执行时间,那所有Message都未到, // 队列里的Message都属于Future Message, // 直接调用removeAllMessagesLocked即可。 if (p.when > now) { removeAllMessagesLocked(); } else { // Message n; for (;;) { n = p.next; // 到这里说明,队列中的Message都在投递状态, // 都不属于Future Message,所以直接return。 if (n == null) { return; } // 找到了还未到执行时间的msg, // 那么它后面的肯定也都是Future msg // 退出遍历循环即可。 if (n.when > now) { break; } // p = n; } // 此时的n属于找到的第一个Future Message // 此时p 是 n的前一个Message // 下面要把p后面,从n开始的msg全部回收 p.next = null; do { p = n; n = p.next; p.recycleUnchecked(); } while (n != null); } } }
6、 Message 池管理
最后有必要再看下 Message 的池管理。
有一个池子,里面原来是空的,当我们创建一个 Message 使用完进行回收后,并没有把这个 Message 对象销毁,而是放到了这个池子里,这个池子最大能容纳 50 个 Message 对象。当需要创建 Message 对象使用时,可以查看下池子是否为空,如果不是,就取一个拿出来使用。这样可以避免创建更多的 Message 对象,一定程度上达到节省内存和申请对象带来的开销。
Message 池也使用了单项链表的数据结构。
// frameworks/base/core/java/android/os/Message.java // 下面几个变量是管理Message池子的一些工具变量 /** @hide */ public static final Object sPoolSync = new Object(); // sPool是池子的表头元素 private static Message sPool; // 池子中的Message元素个数 private static int sPoolSize = 0; // 最大能存放50个Message元素 private static final int MAX_POOL_SIZE = 50; // Android 5.0之后这个值都为true private static boolean gCheckRecycle = true; /** * Return a new Message instance from the global pool. Allows us to * avoid allocating new objects in many cases. */ public static Message obtain() { // 如果池子不是空的,则将其表头Message拿出来返回 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(); }
Message 的回收函数
public void recycle() { // 如果回收正在使用的msg,则抛出异常 if (isInUse()) { if (gCheckRecycle) { throw new IllegalStateException("This message cannot be recycled because it " + "is still in use."); } return; } recycleUnchecked(); } void recycleUnchecked() { // Mark the message as in use while it remains in the recycled object pool. // Clear out all other details. // 回收过程中设置为正在使用状态 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; // 如果当前线程池的Message数量小于MAX_POOL_SIZE, // 则将当前回收的Message放入表头,sPoolSize递增 synchronized (sPoolSync) { if (sPoolSize < MAX_POOL_SIZE) { next = sPool; sPool = this; sPoolSize++; } } }