// MessageQueue.java booleanenqueueMessage(Message msg, long when) { ... // 内置锁(由系统控制 lock 和 unlock),对所有调用同一个 MQ 对象的线程来说都是互斥的 // 1线程->1Looper->1MQ,所以主线程就只有一个 MQ 对象,那么所有子线程向主线程发送消息的时候, // 主线程一次只处理一个消息,其他消息都需要等待,如此消息队列就不会混乱 synchronized (this) { ... msg.markInUse(); msg.when = when; Messagep= mMessages; // 当前链表头结点 boolean needWake; if (p == null || when == 0 || when < p.when) { // 插入队列头部 // New head, wake up the event queue if blocked. msg.next = p; mMessages = msg; needWake = mBlocked; } else { // 根据 when 值插入到适当位置 // 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. needWake = mBlocked && p.target == null && msg.isAsynchronous(); 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); } } returntrue; }
MessageQueue 中有一个 Message mMessages 属性,代表消息队列头节点,向消息队列中插入消息时,如果 p==null(消息队列为空)|| when == 0 || when < p.when(当前要插入消息的 when 小于消息队列头节点的 when),则把当前消息插入到消息队列头节点,并且赋给 mMessages;
// MessageQueue.java 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. finallongptr= mPtr; if (ptr == 0) { returnnull; }
intpendingIdleHandlerCount= -1; // -1 only during first iteration // -1:一直阻塞不会超时;0:不会阻塞,立即返回;>0:最长阻塞时间(毫秒) intnextPollTimeoutMillis=0; for (;;) { if (nextPollTimeoutMillis != 0) { Binder.flushPendingCommands(); }
nativePollOnce(ptr, nextPollTimeoutMillis); // 阻塞多久 // 此处加锁的目的是为了 next() 函数和 enqueueMessage() 函数互斥,如此插入消息和读取消息就会互斥, // 才能保证多线程访问的时候 MQ 的有序进行 synchronized (this) { // Try to retrieve the next message. Return if found. finallongnow= SystemClock.uptimeMillis(); // 获取系统开机到现在的时间 MessageprevMsg=null; Messagemsg= mMessages; // 当前链表的头结点 if (msg != null && msg.target == null) { // 如果 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()); } if (msg != null) { // 如果有消息需要处理,先判断时间有没有到,如果没到设置需要阻塞的时间,比如 postDelay 场景 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. mBlocked = false; // 链表操作,获取 msg 并删除该节点 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 { // No more messages. nextPollTimeoutMillis = -1; // 如果没有消息需要处理,就进入休眠,直到被唤醒 }
// Process the quit message now that all pending messages have been handled. if (mQuitting) { dispose(); returnnull; }
// MessageQueue.java Message next() { intpendingIdleHandlerCount= -1; // -1 only during first iteration intnextPollTimeoutMillis=0; // -1: 一直阻塞,0: 不阻塞,>0: 阻塞毫秒数 ... if (mQuitting) { dispose(); returnnull; }
if (pendingIdleHandlerCount < 0 && (mMessages == null || now < mMessages.when)) { // 如果消息队列为空或者消息还没到触发时间,则当前队列为空闲状态 pendingIdleHandlerCount = mIdleHandlers.size(); } if (pendingIdleHandlerCount <= 0) { // No idle handlers to run. Loop and wait some more. mBlocked = true; continue; }
if (mPendingIdleHandlers == null) { // 如果数组为 null,创建数组 mPendingIdleHandlers = newIdleHandler[Math.max(pendingIdleHandlerCount, 4)]; } // 从 mIdleHandlers 这个列表获取 IdleHandler 元素 mPendingIdleHandlers = mIdleHandlers.toArray(mPendingIdleHandlers); } // 遍历 mPendingIdleHandlers 数组,调用每个 IdleHandler 的 queueIdle() 方法 for (inti=0; i < pendingIdleHandlerCount; i++) { finalIdleHandleridler= mPendingIdleHandlers[i]; mPendingIdleHandlers[i] = null; // release the reference to the handler
// Reset the idle handler count to 0 so we do not run them again. pendingIdleHandlerCount = 0; // 重置 IdleHandler 数量为 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. nextPollTimeoutMillis = 0; // 重置为 0,使之不阻塞 } }
// MessageQueue.java @UnsupportedAppUsage @TestApi publicintpostSyncBarrier() { return postSyncBarrier(SystemClock.uptimeMillis()); } privateintpostSyncBarrier(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) { finalinttoken= mNextBarrierToken++; // 生成同步屏障消息,同步屏障消息没有 target finalMessagemsg= Message.obtain(); msg.markInUse(); msg.when = when; msg.arg1 = token; // 把 token 赋给 msg 的 arg1
// MessageQueue.java @UnsupportedAppUsage @TestApi publicvoidremoveSyncBarrier(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) { Messageprev=null; Messagep= mMessages; // 根据 token 查找同步屏障消息 while (p != null && (p.target != null || p.arg1 != token)) { prev = p; p = p.next; } // 如果这里为 null,说明这个 token 对应的同步屏障消息要么还没有添加到消息队列中;要么已经被移除掉了,抛出异常 if (p == null) { thrownewIllegalStateException("The specified message queue synchronization " + " barrier token has not been posted or has already been removed."); } finalboolean needWake; if (prev != null) { // 从消息队列中移除同步屏障消息;当前消息循环已经在运行中,不需要再次唤醒 prev.next = p.next; needWake = false; } else { // 同步屏障消息位于消息队列第一个,从消息队列中移除同步屏障 mMessages = p.next; // 当前消息循环为阻塞状态,如果下一个消息为null,或者下一个消息的 target 不为 null,则唤醒消息循环 needWake = mMessages == null || mMessages.target != null; } p.recycleUnchecked(); // 回收 Message 消息,循环利用
// If the loop is quitting then it is already awake. // We can assume mPtr != 0 when mQuitting is false. if (needWake && !mQuitting) { nativeWake(mPtr); } } }
// Handler.java publicfinalbooleanrunWithScissors(@NonNull Runnable r, long timeout) { if (r == null) { thrownewIllegalArgumentException("runnable must not be null"); } if (timeout < 0) { thrownewIllegalArgumentException("timeout must be non-negative"); }