// 如果消息循环已经退出了。则直接在这里return。因为调用disposed()方法后mPtr=0 // 其实就是底层的NativeMessageQueue的应用已经被释放 finallongptr= mPtr; if (ptr == 0) { returnnull; } // 记录空闲时处理的IdlerHandler的数量 intpendingIdleHandlerCount= -1; // -1 only during first iteration // native层用到的变量 ,如果消息尚未到达处理时间,则表示为距离该消息处理事件的总时长, // 表明Native Looper只需要block到消息需要处理的时间就行了。 所以nextPollTimeoutMillis>0表示还有消息待处理 intnextPollTimeoutMillis=0;
// 这个地方就是一个死循环.这个里面的死循环并不会造成卡死。会产生block for (;;) { if (nextPollTimeoutMillis != 0) { // 刷新下Binder命令,一般在阻塞前调用 Binder.flushPendingCommands(); } // 调用native层进行消息标示,nextPollTimeoutMillis 为0立即返回,为-1则阻塞等待。 // 就是这行代码进行消息阻塞的。这当代码会调用Native层的Looper::pollOnce()的方法. // 如果是-1.造成阻塞等待。则会释放出CPU。 nativePollOnce(ptr, nextPollTimeoutMillis); // 消息的遍历需要加上同步锁 synchronized (this) { // 获取开机到现在的时间。还记得咱们执行Handler#sendMessageAtTime(SystemClock.uptimeMillis()+delay)?? finallongnow= SystemClock.uptimeMillis(); // 开始进行遍历队列。找到下一条要执行的消息。如果找到则返回该消息msg MessageprevMsg=null; Messagemsg= mMessages; // 如果头部消息不为null 但是是一个同步屏障消息(同步屏障消息的msg.target为null) // 这个时候我们只能遍历同步屏障消息后面的异步消息 // 关于同步屏障的问题,我们可以参考#ViewRootImpl#scheduleTraversals的方法 // 如果是则执行循环,拦截所有同步消息,直到取到第一个异步消息为止 // 进入do while循环,遍历链表,直到找到异步消息msg.isAsynchronous()才跳出循环交给Handler去处理这个异步消息。 if (msg != null && msg.target == null) { // Stalled by a barrier. Find the next asynchronous message in the queue. do { // 如果能进入这个if,则表明MessageQueue的第一个元素就是障栅(barrier) prevMsg = msg; msg = msg.next; // 如果msg==null或者msg是异步消息则退出循环,msg==null则意味着已经循环结束 } while (msg != null && !msg.isAsynchronous());
} // 找到消息队列的第一个消息。或者是屏障消息后面的第一个异步消息之后 // 下面就是看这个消息是否已经到了对应的触发时间 if (msg != null) { // 如果当前时间now小于msg.when 说明还未到第一个可处理消息的时间 if (now < msg.when) { // Next message is not ready. Set a timeout to wake up when it is ready. // 当Message还没有到可处理时间的时候,记录下一次要执行的Message的时间点 nextPollTimeoutMillis = (int) Math.min(msg.when - now, Integer.MAX_VALUE); } else { // 这种情况是正常情况下,第一个可处理消息已经到了处理时间。 // 从队列中取出该Message,并重新构建原来队列的连接关系 // Got a message.找到了可处理消息,自然就不需要block了。 mBlocked = false; // 如果还有上一个元素 上一个元素的next(越过当前可处理消息)直接指向下一个元素 if (prevMsg != null) { prevMsg.next = msg.next; } else { // 如果没有上一个元素,则说明是消息队列中的头元素,直接让第二个元素变成头元素 mMessages = msg.next; } msg.next = null; if (DEBUG) Log.v(TAG, "Returning message: " + msg); // 标记该Message为正处于使用状态,然后返回Message msg.markInUse(); return msg; } } else { // No more messages. 如果消息队列里面没有任何消息。则nextPollTimeoutMillis为-1 // 也就是上面说的nativePollOnce的长时间阻塞,让出CPU nextPollTimeoutMillis = -1; }
// Process the quit message now that all pending messages have been handled. // 如果已经关闭消息队列,返回null,通知Looper停止循环。这个在主线程消息队列是不会出现的 if (mQuitting) { dispose(); returnnull; }
// 下面是关于IdleHandler的逻辑处理方法。个人认为这块逻辑其实不是next方法的实现。最好能作为一个方法抽离出现、 // 放在next方法里面增加next方法的阅读性 // 函数执行到这个地方说明两点: // 1、消息队列中已经没有消息 // 2、消息队列中中最头部的消息都还没有到处理时间 // 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(); } // 如果没有等待的IdleHandler。则标记消息mBlocked。重新遍历 if (pendingIdleHandlerCount <= 0) { // No idle handlers to run. Loop and wait some more. mBlocked = true; continue; } // 执行到这个地方。说明有IdleHanlder插入。这个时候我们纪要创建IdleHandler if (mPendingIdleHandlers == null) { mPendingIdleHandlers = newIdleHandler[Math.max(pendingIdleHandlerCount, 4)]; } mPendingIdleHandlers = mIdleHandlers.toArray(mPendingIdleHandlers); }
// Run the idle handlers. // We only ever reach this code block during the first iteration. for (inti=0; i < pendingIdleHandlerCount; i++) { // 一次获取等待的IdleHandler finalIdleHandleridler= mPendingIdleHandlers[i]; mPendingIdleHandlers[i] = null; // release the reference to the handler
if (!keep) { synchronized (this) { mIdleHandlers.remove(idler); } } }
// Reset the idle handler count to 0 so we do not run them again. // 处理完IdleHandler之后将pendingIdleHandlerCount设置为0 pendingIdleHandlerCount = 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. // 处理完IdleHandler之后我们在nextPollTimeoutMillis设置完 nextPollTimeoutMillis = 0; } }