Android源码学习 Handler之MessageQueue

Posted 荆棘鸟

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Android源码学习 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;
        }
    }
}

 

以上是关于Android源码学习 Handler之MessageQueue的主要内容,如果未能解决你的问题,请参考以下文章

Android源码学习 Handler之ThreadLocal

Android :安卓学习笔记之 Handler机制 的简单理解和使用

Android Handler消息机制02-Looper源码学习

Android Handler消息机制02-Looper源码学习

Android源码学习 Handler

Android Handler消息机制02-Looper源码学习