Android源码学习(3) Handler之MessageQueue
消息出队
MessageQueue封装了以单向列表实现的Message队列。在Looper循环中,通过调用MessageQueue的next()方法将队首元素出队进行处理:
1 Message next() { 2 // Return here if the message loop has already quit and been disposed. 3 // This can happen if the application tries to restart a looper after quit 4 // which is not supported. 5 final long ptr = mPtr; 6 if (ptr == 0) { 7 return null; 8 } 9 10 int pendingIdleHandlerCount = -1; // -1 only during first iteration 11 int nextPollTimeoutMillis = 0; 12 for (;;) { 13 if (nextPollTimeoutMillis != 0) { 14 Binder.flushPendingCommands(); 15 } 16 17 nativePollOnce(ptr, nextPollTimeoutMillis); 18 19 synchronized (this) { 20 // Try to retrieve the next message. Return if found. 21 final long now = SystemClock.uptimeMillis(); 22 Message prevMsg = null; 23 Message msg = mMessages; 24 if (msg != null && msg.target == null) { 25 // Stalled by a barrier. Find the next asynchronous message in the queue. 26 do { 27 prevMsg = msg; 28 msg = msg.next; 29 } while (msg != null && !msg.isAsynchronous()); 30 } 31 if (msg != null) { 32 if (now < msg.when) { 33 // Next message is not ready. Set a timeout to wake up when it is ready. 34 nextPollTimeoutMillis = (int) Math.min(msg.when - now, Integer.MAX_VALUE); 35 } else { 36 // Got a message. 37 mBlocked = false; 38 if (prevMsg != null) { 39 prevMsg.next = msg.next; 40 } else { 41 mMessages = msg.next; 42 } 43 msg.next = null; 44 if (DEBUG) Log.v(TAG, "Returning message: " + msg); 45 msg.markInUse(); 46 return msg; 47 } 48 } else { 49 // No more messages. 50 nextPollTimeoutMillis = -1; 51 } 52 53 // Process the quit message now that all pending messages have been handled. 54 if (mQuitting) { 55 dispose(); 56 return null; 57 } 58 59 // If first time idle, then get the number of idlers to run. 60 // Idle handles only run if the queue is empty or if the first message 61 // in the queue (possibly a barrier) is due to be handled in the future. 62 if (pendingIdleHandlerCount < 0 63 && (mMessages == null || now < mMessages.when)) { 64 pendingIdleHandlerCount = mIdleHandlers.size(); 65 } 66 if (pendingIdleHandlerCount <= 0) { 67 // No idle handlers to run. Loop and wait some more. 68 mBlocked = true; 69 continue; 70 } 71 72 if (mPendingIdleHandlers == null) { 73 mPendingIdleHandlers = new IdleHandler[Math.max(pendingIdleHandlerCount, 4)]; 74 } 75 mPendingIdleHandlers = mIdleHandlers.toArray(mPendingIdleHandlers); 76 } 77 78 // Run the idle handlers. 79 // We only ever reach this code block during the first iteration. 80 for (int i = 0; i < pendingIdleHandlerCount; i++) { 81 final IdleHandler idler = mPendingIdleHandlers[i]; 82 mPendingIdleHandlers[i] = null; // release the reference to the handler 83 84 boolean keep = false; 85 try { 86 keep = idler.queueIdle(); 87 } catch (Throwable t) { 88 Log.wtf(TAG, "IdleHandler threw exception", t); 89 } 90 91 if (!keep) { 92 synchronized (this) { 93 mIdleHandlers.remove(idler); 94 } 95 } 96 } 97 98 // Reset the idle handler count to 0 so we do not run them again. 99 pendingIdleHandlerCount = 0; 100 101 // While calling an idle handler, a new message could have been delivered 102 // so go back and look again for a pending message without waiting. 103 nextPollTimeoutMillis = 0; 104 } 105 }
当队首元素执行时间未 或 队首元素为SyncBarrier且队列中没有asynchronous的Message 或 队列为空时,会执行IdleHandler(通过addIdleHandler和removeIdleHandler进行添加和移除)的queueIdle回调或者睡眠(nativePollOnce)。nativePollOnce与OnFileDescriptorEventListener相关,底层是基于Linux的epoll实现的,具体能用来干啥笔者也并不清楚,此处就把它当作定时睡眠操作吧。
第24行,对msg.target判空,通过postSyncBarrier发送的Message的target字段为空,即当队首Message是SyncBarrier时,会在队列中查找asynchronous的Message进行处理,而非asynchronous的Message将被阻塞。
第54行,若mQuitting为真,则返回null,从而导致Looper退出循环,结束Looper的执行。
消息入队
向Handler上发送消息,最终都通过enqueueMessage放入MessageQueue队列中:
1 boolean enqueueMessage(Message msg, long when) { 2 if (msg.target == null) { 3 throw new IllegalArgumentException("Message must have a target."); 4 } 5 if (msg.isInUse()) { 6 throw new IllegalStateException(msg + " This message is already in use."); 7 } 8 9 synchronized (this) { 10 if (mQuitting) { 11 IllegalStateException e = new IllegalStateException( 12 msg.target + " sending message to a Handler on a dead thread"); 13 Log.w(TAG, e.getMessage(), e); 14 msg.recycle(); 15 return false; 16 } 17 18 msg.markInUse(); 19 msg.when = when; 20 Message p = mMessages; 21 boolean needWake; 22 if (p == null || when == 0 || when < p.when) { 23 // New head, wake up the event queue if blocked. 24 msg.next = p; 25 mMessages = msg; 26 needWake = mBlocked; 27 } else { 28 // Inserted within the middle of the queue. Usually we don't have to wake 29 // up the event queue unless there is a barrier at the head of the queue 30 // and the message is the earliest asynchronous message in the queue. 31 needWake = mBlocked && p.target == null && msg.isAsynchronous(); 32 Message prev; 33 for (;;) { 34 prev = p; 35 p = p.next; 36 if (p == null || when < p.when) { 37 break; 38 } 39 if (needWake && p.isAsynchronous()) { 40 needWake = false; 41 } 42 } 43 msg.next = p; // invariant: p == prev.next 44 prev.next = msg; 45 } 46 47 // We can assume mPtr != 0 because mQuitting is false. 48 if (needWake) { 49 nativeWake(mPtr); 50 } 51 } 52 return true; 53 }
enqueueMessage通过when字段维护队列中Message的先后循序。
第22行,当队列为空 或 when为0 或 when小于队首元素的when,则将Message放入队首。通过Handler的postAtFrontOfQueue和sendMessageAtFrontOfQueue提交的Runnable和Message满足when为0。
消息移除
removeMessages(Handler h, int what, Object object)、removeMessages(Handler h, Runnable r, Object object)、removeCallbacksAndMessages(Handler h, Object object)用于移除消息。这三个函数底层实现基本类似,分两步操作:1) 循环移除满足条件的Message,直到其不位于队首;2) 移除剩余的满足条件Message:
void removeMessages(Handler h, int what, Object object) { if (h == null) { return; } synchronized (this) { Message p = mMessages; // Remove all messages at front. while (p != null && p.target == h && p.what == what && (object == null || p.obj == object)) { Message n = p.next; mMessages = n; p.recycleUnchecked(); p = n; } // Remove all messages after front. 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; } } }