基于 Android 7.1.1 源码,分析 handler 的架构和原理。
1 成员变量 1 private final boolean mQuitAllowed;
该变量表示 MessageQueue 是否可以退出,主线程的消息队列不可退出。
1 2 @SuppressWarnings ("unused" )private long mPtr;
java 层有一个 MessageQueue,同样的 native 层也有一个 MessageQueue,java 层 MessageQueue 在初始化是,也会初始化 native 层的 MessageQueue,这个变量用来保存 natvie 层的消息队列的句柄!
MessageQueue 消息队列中的所有消息是通过链表联系在一起的,mMessages 是这个链表的头元素!
1 private IdleHandler[] mPendingIdleHandlers;
用于保存将要被执行的 IdleHandler,当消息队列要执行 IdleHandler 的时候,他会将 mIdleHandlers 中的所有 IdleHandler 拷贝到 mPendingIdleHandlers!
1 private final ArrayList<IdleHandler> mIdleHandlers = new ArrayList<IdleHandler>();
用于保存该线程的所有 IdleHandler!
1 private SparseArray<FileDescriptorRecord> mFileDescriptorRecords;
用于记录文件描述符
1 private boolean mQuitting;
该变量表示 MessageQueue 是否正在关闭退出!
1 private boolean mBlocked;
该变量表示 MessageQueue 是否是阻塞的,当 MessageQueue 中没有任何消息的时候,消息队列会阻塞,等待消息的插入!
1 private int mNextBarrierToken;
这里要提及一个概念叫:障栅(Barrier)。
障栅是一个特殊的 Message,他的 target 为 null,并且其 Message.arg1 作为句柄,标识每一个独一无二的障栅!
障栅的作用很重要,它能够拦截同步 Message,阻止同步消息被执行,放行异步 Message!后面我们会看到!
mNextBarrierToken 的作用是计算下一个 Barrier 的 token!
2 create MessageQueue 我们来回顾下 Looper 的创建:1 2 3 4 private Looper (boolean quitAllowed) { mQueue = new MessageQueue(quitAllowed); mThread = Thread.currentThread(); }
2.1 new MessageQueue 这里会调用 MessageQueue 构造器,创建一个消息队列!
1 2 3 4 MessageQueue(boolean quitAllowed) { mQuitAllowed = quitAllowed; mPtr = nativeInit(); }
mQuitAllowed 成员变量表示该消息队列是否可以关闭 ,对于 ui 线程的消息队列,是不能退出的,我们可以回顾下,ui 线程的 Looper 创建:
1 2 3 4 5 6 7 8 9 public static void prepareMainLooper () { prepare(false ); synchronized (Looper.class) { if (sMainLooper != null ) { throw new IllegalStateException("The main Looper has already been prepared." ); } sMainLooper = myLooper(); } }
nativeInit 方法是一个 native 方法,他会初始化处于 native 层的 MessageQueue,他和 java 层的 MessageQueue 一一对应!
在 Android 2.3 之前,只有 java 层才可以向 MessageQueue 中添加消息,在 Android 2.3 之后,MessageQueue 的核心部分移动到了 native 层。这样,java 层和 native 层都可以使用 MessageQueue!
也就是说, Java 层的 MessageQueue 处理 Java 层的消息,natvie 层的 MessageQueue 负责处理 native 层的消息!
3 enqueue Message 我们回到 Handler 中,当我们通过 handler 发送消息的时候,会调用 Handler.enqueueMessage 方法:
1 2 3 4 5 6 7 private boolean enqueueMessage (MessageQueue queue, Message msg, long uptimeMillis) { msg.target = this ; if (mAsynchronous) { msg.setAsynchronous(true ); } return queue.enqueueMessage(msg, uptimeMillis); }
3.1 MessageQueue.enqueueMessage 最终会调用 enqueueMessage 将消息插入到 MessageQueue 中,下面我们来看看 MessageQueue.enqueueMessage 方法:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 boolean enqueueMessage (Message msg, long when) { 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 ) { 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) { 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; prev.next = msg; } if (needWake) { nativeWake(mPtr); } } return true ; }
这里来说下 MessageQueue 的成员变量 mMessages:在 MessageQueue 中,所有的 Message 是以链表的形式组织在一起的,mMessages 是链表的头元素!
4 dispatch Message 在前面 Looper 分析中,我们知道,Looper.loop() 方法会进入一个 for 死循环,不断的调用 MessageQueue.next 方法,返回下一个 Message。
4.1 MessageQueue.next 下面我们来看看 MessageQueue.next 方法:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 Message next () { final long ptr = mPtr; if (ptr == 0 ) { return null ; } int pendingIdleHandlerCount = -1 ; int nextPollTimeoutMillis = 0 ; for (;;) { if (nextPollTimeoutMillis != 0 ) { Binder.flushPendingCommands(); } nativePollOnce(ptr, nextPollTimeoutMillis); synchronized (this ) { final long now = SystemClock.uptimeMillis(); Message prevMsg = null ; Message msg = mMessages; if (msg != null && msg.target == null ) { do { prevMsg = msg; msg = msg.next; } while (msg != null && !msg.isAsynchronous()); } if (msg != null ) { if (now < msg.when) { nextPollTimeoutMillis = (int ) Math.min(msg.when - now, Integer.MAX_VALUE); } else { mBlocked = false ; if (prevMsg != null ) { prevMsg.next = msg.next; } else { mMessages = msg.next; } msg.next = null ; if (DEBUG) Log.v(TAG, "Returning message: " + msg); msg.markInUse(); return msg; } } else { nextPollTimeoutMillis = -1 ; } if (mQuitting) { dispose(); return null ; } if (pendingIdleHandlerCount < 0 && (mMessages == null || now < mMessages.when)) { pendingIdleHandlerCount = mIdleHandlers.size(); } if (pendingIdleHandlerCount <= 0 ) { mBlocked = true ; continue ; } if (mPendingIdleHandlers == null ) { mPendingIdleHandlers = new IdleHandler[Math.max(pendingIdleHandlerCount, 4 )]; } mPendingIdleHandlers = mIdleHandlers.toArray(mPendingIdleHandlers); } for (int i = 0 ; i < pendingIdleHandlerCount; i++) { final IdleHandler idler = mPendingIdleHandlers[i]; mPendingIdleHandlers[i] = null ; boolean keep = false ; try { keep = idler.queueIdle(); } catch (Throwable t) { Log.wtf(TAG, "IdleHandler threw exception" , t); } if (!keep) { synchronized (this ) { mIdleHandlers.remove(idler); } } } pendingIdleHandlerCount = 0 ; nextPollTimeoutMillis = 0 ; } }
方法逻辑:
查询下一个要触发的消息:next 方法会启动一个 for 循环,顺序遍历消息链表:
如果头消息是障栅,那就顺序查找下一个异步消息!
如果头消息不是障栅,那么那其就是同步消息,也是我们即将分发的消息!
当 MessageQueue 退出关闭的时候,mQuitting 会被置为 true,这样 MessageQueue.next 会返回一个 null 的 Message,回顾 Looper.loop,消息循环就可以退出了!
1 2 3 void markInUse () { flags |= FLAG_IN_USE; }
将一个 message 设置为正在使用的状态!
5 quit MessageQueue 回顾 Looper.quit 方法:1 2 3 public void quit () { mQueue.quit(false ); }
当我们不想使用消息队列了,我们可以关闭它,最终调用的 MessageQueue.quit 方法:
5.1 MessageQueue.quit 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 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(); } nativeWake(mPtr); } }
方法逻辑:
设置 mQuitting 为 true;
如果是安全关闭,调用 removeAllFutureMessagesLocked 移除当前时间点以后未分发的消息;
如果是非安全关闭,调用 removeAllMessagesLocked 移除所有的消息;
6 remove Message 回顾 Handler。Handler 提供了 remove 方法:
1 2 3 public final void removeMessages (int what) { mQueue.removeMessages(this , what, null ); }
最终调用了 MessageQueue 的 removeMessages 方法!
MessageQueue 有多个 remove 方法,我们一个一个来看:
6.1 MessageQueue.removeMessages
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 void removeMessages (Handler h, int what, Object object) { if (h == null ) { return ; } synchronized (this ) { Message p = mMessages; while (p != null && p.target == h && p.what == what && (object == null || p.obj == object)) { Message n = p.next; mMessages = n; p.recycleUnchecked(); p = n; } while (p != null ) { Message n = p.next; if (n != null ) { if (n.target == h && n.what == what && (object == null || n.obj == object)) { Message nn = n.next; n.recycleUnchecked(); p.next = nn; continue ; } } p = n; } } }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 void removeMessages (Handler h, Runnable r, Object object) { if (h == null || r == null ) { return ; } synchronized (this ) { Message p = mMessages; while (p != null && p.target == h && p.callback == r && (object == null || p.obj == object)) { Message n = p.next; mMessages = n; p.recycleUnchecked(); p = n; } while (p != null ) { Message n = p.next; if (n != null ) { if (n.target == h && n.callback == r && (object == null || n.obj == object)) { Message nn = n.next; n.recycleUnchecked(); p.next = nn; continue ; } } p = n; } } }
不管是移除 Messages 还是移除 Runnable,流程都是一样的:
先从头消息开始进行第一阶段的匹配,如果能够匹配,就移除头消息,并更新链表头!
当头消息无法匹配,那么我们就删除剩下的消息中能够匹配的消息!
6.2 MessageQueue.removeCallbacksAndMessages 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 void removeCallbacksAndMessages (Handler h, Object object) { if (h == null ) { return ; } synchronized (this ) { Message p = mMessages; while (p != null && p.target == h && (object == null || p.obj == object)) { Message n = p.next; mMessages = n; p.recycleUnchecked(); p = n; } while (p != null ) { Message n = p.next; if (n != null ) { if (n.target == h && (object == null || n.obj == object)) { Message nn = n.next; n.recycleUnchecked(); p.next = nn; continue ; } } p = n; } } }
6.3 MessageQueue.removeAllMessagesLocked 移除消息队列中所有的 Message!
1 2 3 4 5 6 7 8 9 private void removeAllMessagesLocked () { Message p = mMessages; while (p != null ) { Message n = p.next; p.recycleUnchecked(); p = n; } mMessages = null ; }
方法很简单,不多说!
6.4 MessageQueue.removeAllFutureMessagesLocked 移除消息队列中当前时间下所有未分发的 Message!
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 private void removeAllFutureMessagesLocked () { final long now = SystemClock.uptimeMillis(); Message p = mMessages; if (p != null ) { if (p.when > now) { removeAllMessagesLocked(); } else { Message n; for (;;) { n = p.next; if (n == null ) { return ; } if (n.when > now) { break ; } p = n; } p.next = null ; do { p = n; n = p.next; p.recycleUnchecked(); } while (n != null ); } } }
方法很简单,不多说!!
7 障栅 Barrier 我们知道障栅本质上是一个特殊的 Message,其 target 为 null,他能够拦截同步的消息,放行异步消息 !!
我们关心的是如何向消息队列中插入和移除障栅!!
7.1 MessageQueue.postSyncBarrier MessageQueue 提供了 postSyncBarrier 来向消息队列中增加障栅 Barrier!
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 public int postSyncBarrier () { return postSyncBarrier(SystemClock.uptimeMillis()); } private int postSyncBarrier (long when) { synchronized (this ) { final int token = mNextBarrierToken++; final Message msg = Message.obtain(); msg.markInUse(); msg.when = when; msg.arg1 = token; Message prev = null ; Message p = mMessages; if (when != 0 ) { while (p != null && p.when <= when) { prev = p; p = p.next; } } if (prev != null ) { msg.next = p; prev.next = msg; } else { msg.next = p; mMessages = msg; } return token; } }
参数 when 表示障栅的拦截时间点!
可以看到,当我们插入障栅后,其要么是位于消息队列的头,要么是根据拦截时间 when,将障栅插入到消息队列的合适位置!
这样,障栅就可以拦截其后的所有同步消息了!
7.2 MessageQueue.removeSyncBarrier MessageQueue 提供了 removeSyncBarrier 来从消息队列中移除障栅 Barrier:
参数 token 用于识别指定的障珊!
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 public void removeSyncBarrier (int token) { synchronized (this ) { Message prev = null ; Message p = mMessages; while (p != null && (p.target != null || p.arg1 != token)) { prev = p; p = p.next; } if (p == null ) { throw new IllegalStateException("The specified message queue synchronization " + " barrier token has not been posted or has already been removed." ); } final boolean needWake; if (prev != null ) { prev.next = p.next; needWake = false ; } else { mMessages = p.next; needWake = mMessages == null || mMessages.target != null ; } p.recycleUnchecked(); if (needWake && !mQuitting) { nativeWake(mPtr); } } }
逻辑很简单,就是遍历消息队列,根据传入的 token,匹配合适的障栅!!
我们为什么要 remove 掉障栅?
道理很简单,由于障栅是一种特殊的 message,其 target 为 null,所以其不能被分发,意味着如果障栅后面没有异步消息,那么整个队列就会一直阻塞下去!!
8 Native 层分析 上面分析了 java 层的 MessageQueue 逻辑架构,但我们早已经知道 native 也有个 MessageQueue,java 层的消息队列可通过以下方法和 native 层的 MessageQueue 通信:1 2 3 4 5 6 private native static long nativeInit () ;private native static void nativeDestroy (long ptr) ;private native void nativePollOnce (long ptr, int timeoutMillis) ; private native static void nativeWake (long ptr) ;private native static boolean nativeIsPolling (long ptr) ;private native static void nativeSetFileDescriptorEvents (long ptr, int fd, int events) ;
native 层的 MessageQueue 除了可以让 native 层实现消息通信机制,更重要的是,其能够保证 java 层的不会陷入死循环!!
对应的 native 层方法位于 android/frameworks/base/core/jni/android_os_MessageQueue.cpp 文件中!
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 static const JNINativeMethod gMessageQueueMethods[] = { { "nativeInit" , "()J" , (void *)android_os_MessageQueue_nativeInit }, { "nativeDestroy" , "(J)V" , (void *)android_os_MessageQueue_nativeDestroy }, { "nativePollOnce" , "(JI)V" , (void *)android_os_MessageQueue_nativePollOnce }, { "nativeWake" , "(J)V" , (void *)android_os_MessageQueue_nativeWake }, { "nativeIsPolling" , "(J)Z" , (void *)android_os_MessageQueue_nativeIsPolling }, { "nativeSetFileDescriptorEvents" , "(JII)V" , (void *)android_os_MessageQueue_nativeSetFileDescriptorEvents }, }; int register_android_os_MessageQueue (JNIEnv* env) { int res = RegisterMethodsOrDie(env, "android/os/MessageQueue" , gMessageQueueMethods, NELEM(gMessageQueueMethods)); jclass clazz = FindClassOrDie(env, "android/os/MessageQueue" ); gMessageQueueClassInfo.mPtr = GetFieldIDOrDie(env, clazz, "mPtr" , "J" ); gMessageQueueClassInfo.dispatchEvents = GetMethodIDOrDie(env, clazz, "dispatchEvents" , "(II)I" ); return res; }
register_android_os_MessageQueue 用来注册静态方法!
8.1 android_os_MessageQueue_nativeInit 我们来看一下这个 nativeInit 对应的 native 方法:
1 2 3 4 5 6 7 8 9 10 11 static jlong android_os_MessageQueue_nativeInit (JNIEnv* env, jclass clazz) { NativeMessageQueue* nativeMessageQueue = new NativeMessageQueue(); if (!nativeMessageQueue) { jniThrowRuntimeException(env, "Unable to allocate native queue" ); return 0 ; } nativeMessageQueue->incStrong(env); return reinterpret_cast<jlong>(nativeMessageQueue); }
这里创建了 native 层的消息队列:NativeMessageQueue!
1 2 3 4 5 6 7 8 NativeMessageQueue::NativeMessageQueue() : mPollEnv(NULL), mPollObj(NULL), mExceptionObj(NULL) { mLooper = Looper::getForThread(); if (mLooper == NULL) { mLooper = new Looper(false ); Looper::setForThread(mLooper); } }
8.1 android_os_MessageQueue_nativePollOnce 1 2 3 4 5 static void android_os_MessageQueue_nativePollOnce (JNIEnv* env, jobject obj, jlong ptr, jint timeoutMillis) { NativeMessageQueue* nativeMessageQueue = reinterpret_cast<NativeMessageQueue*>(ptr); nativeMessageQueue->pollOnce(env, obj, timeoutMillis); }
9 总结 下面我们来总结下 MessageQueue 的类图!