MessageQueue在消息機制中主要負責維護Message的鏈表結構,以及當有新Message進來時向Looper提供新Message,MessageQueue字義上看起來是消息隊列的意思,但其數據結構其實是一個單鏈表的結構,從Message類的定義可以看出,裏面有一個變量,指向了下一個Message
// sometimes we store linked lists of these things
enqueueMessage
boolean enqueueMessage(Message msg, long when) {
throw new IllegalArgumentException("Message must have a target.");
throw new IllegalStateException(msg + " This message is already in use.");
IllegalStateException e = new IllegalStateException(
msg.target + " sending message to a Handler on a dead thread");
Log.w(TAG, e.getMessage(), e);
if (p == null || when == 0 || when < p.when) {
// New head, wake up the event queue if blocked.
// 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();
if (p == null || when < p.when) {
if (needWake && p.isAsynchronous()) {
msg.next = p; // invariant: p == prev.next
// We can assume mPtr != 0 because mQuitting is false.
此方法是將一個Message添加到Message鏈表中去,會先對message進行常規判斷,message的handler是否爲空,是否處於可使用的狀態中,以及當前的消息機制是否被停止(由looper調用),當停止時,插入消息失敗
接下來就是鏈表的插入操作,先判斷是否存在表頭,一開始mMessages是爲空的,所以會將當前消息作爲頭部,mMessages作爲當前消息的next
next()
next方法中是一個死循環 不斷從消息鏈表中查詢是否有可用狀態的新消息加入,如果有,則返回給Looper
// 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
int pendingIdleHandlerCount = -1; // -1 only during first iteration
int nextPollTimeoutMillis = 0;
if (nextPollTimeoutMillis != 0) {
Binder.flushPendingCommands();
nativePollOnce(ptr, nextPollTimeoutMillis);
// Try to retrieve the next message. Return if found.
final long now = SystemClock.uptimeMillis();
if (msg != null && msg.target == null) {
// Stalled by a barrier. Find the next asynchronous message in the queue.
} while (msg != null && !msg.isAsynchronous());
// 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);
if (DEBUG) Log.v(TAG, "Returning message: " + msg);
// Process the quit message now that all pending messages have been handled.
// 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.
if (pendingIdleHandlerCount < 0
&& (mMessages == null || now < mMessages.when)) {
pendingIdleHandlerCount = mIdleHandlers.size();
if (pendingIdleHandlerCount <= 0) {
// No idle handlers to run. Loop and wait some more.
if (mPendingIdleHandlers == null) {
mPendingIdleHandlers = new IdleHandler[Math.max(pendingIdleHandlerCount, 4)];
mPendingIdleHandlers = mIdleHandlers.toArray(mPendingIdleHandlers);
// We only ever reach this code block during the first iteration.
for (int i = 0; i < pendingIdleHandlerCount; i++) {
final IdleHandler idler = mPendingIdleHandlers[i];
mPendingIdleHandlers[i] = null; // release the reference to the handler
Log.wtf(TAG, "IdleHandler threw exception", t);
// Reset the idle handler count to 0 so we do not run them again.
// While calling an idle handler, a new message could have been delivered
// so go back and look again for a pending message without waiting.
1.首次進入循環nextPollTimeoutMillis=0,阻塞方法nativePollOnce(ptr, nextPollTimeoutMillis)會立即返回
2.讀取列表中的消息,如果發現消息屏障,則跳過後面的同步消息,總之會通過當前時間,是否遇到屏障來返回符合條件的待處理消息
3.如果沒有符合條件的消息,會處理一些不緊急的任務(IdleHandler),再次進入第一步
1.加入消息比較簡單,按時間順序插入到消息鏈表中,如果是第一個那麼根據mBlocked判斷是否需要喚醒線程,如果不是第一個一般情況下不需要喚醒(如果加入的消息是異步的需要另外判斷)
到這裏其實關於MessageQueue已經分析的差不多了,其中有兩個native方法沒有涉及到分別是nativePollOnce,nativeWake,其實之前結論已經給出了,兩個方法都會傳入mPtr,在native層對應的是NativeMessageQueue的引用地址。