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的引用地址。