Android MessageQueue详解
一、MessageQueue介绍
/** * Low-level class holding the list of messages to be dispatched by a * {@link Looper}. Messages are not added directly to a MessageQueue, * but rather through {@link Handler} objects associated with the Looper. * 低级类,持有一个由Looper分配发送的Message集合。
Message不是直接添加到MessageQueue的,而是通过与Looper相关联的Handler对象来添加。 * <p>You can retrieve the MessageQueue for the current thread with * {@link Looper#myQueue() Looper.myQueue()}.
你可以用Looper.myQueue()方法检索到当前线程的MessageQueue。 */
二、MessageQueue源码
1.IdleHandler
在阅读源码时候看到个有意思的接口:IdleHandler。
这个idleHandler被添加后会在message处理结束后回调,返回false时,说明looper中的message暂时全部处理完,同时IdleHandler会被移除,当返回true时,说明队列中仍有未处理的message,并且在下次message处理完成后继续回掉直到全部message处理完成。
/** * Callback interface for discovering when a thread is going to block * waiting for more messages.
一个回调接口,用于发现线程何时因等待更多消息而阻塞。 */ public static interface IdleHandler { /** * Called when the message queue has run out of messages and will now * wait for more. Return true to keep your idle handler active, false * to have it removed. This may be called if there are still messages * pending in the queue, but they are all scheduled to be dispatched * after the current time.
当消息队列运行完所有消息并等待更多时调用。
返回 true 以保持空闲handle处于活动状态,返回 false 以将其删除。
如果队列中仍有待处理的消息,则可能会调用此方法,但它们都被安排在当前时间之后调度。 */ boolean queueIdle(); /** * Returns true if the looper has no pending messages which are due to be processed.
* 如果 Looper 没有待处理的待处理消息,则返回 true。 * <p>This method is safe to call from any thread.
该方法可以在任意线程安全的调用。 * * @return True if the looper is idle. */ public boolean isIdle() { synchronized (this) { final long now = SystemClock.uptimeMillis(); return mMessages == null || now < mMessages.when; } } /** * Add a new {@link IdleHandler} to this message queue. This may be * removed automatically for you by returning false from * {@link IdleHandler#queueIdle IdleHandler.queueIdle()} when it is * invoked, or explicitly removing it with {@link #removeIdleHandler}. * 在消息队列里添加一个新的IdleHandler。这会在queueIdle()方法调用时返回false自动删除,
或者在removeIdleHandler中明确删除。 * <p>This method is safe to call from any thread. * * @param handler The IdleHandler to be added. */ public void addIdleHandler(@NonNull IdleHandler handler) { if (handler == null) { throw new NullPointerException("Can't add a null IdleHandler"); } synchronized (this) { mIdleHandlers.add(handler); } } /** * Remove an {@link IdleHandler} from the queue that was previously added * with {@link #addIdleHandler}. If the given object is not currently * in the idle list, nothing is done. * * <p>This method is safe to call from any thread. * * @param handler The IdleHandler to be removed. */ public void removeIdleHandler(@NonNull IdleHandler handler) { synchronized (this) { mIdleHandlers.remove(handler); } }
看下调用地方的代码:
Message next() { // 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 // which is not supported. final long ptr = mPtr; if (ptr == 0) { return null; } int pendingIdleHandlerCount = -1; // -1 only during first iteration int nextPollTimeoutMillis = 0; for (;;) { if (nextPollTimeoutMillis != 0) { Binder.flushPendingCommands(); } nativePollOnce(ptr, nextPollTimeoutMillis); synchronized (this) { // Try to retrieve the next message. Return if found. final long now = SystemClock.uptimeMillis(); Message prevMsg = null; Message msg = mMessages; if (msg != null && msg.target == null) { // Stalled by a barrier. Find the next asynchronous message in the queue. do { prevMsg = msg; msg = msg.next; } while (msg != null && !msg.isAsynchronous()); } if (msg != null) { if (now < msg.when) { // 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); } else { // Got a message. mBlocked = false; if (prevMsg != null) { prevMsg.next = msg.next; } else { mMessages = msg.next; } msg.next = null; if (DEBUG) Log.v(TAG, "Returning message: " + msg); msg.markInUse(); return msg; } } else { // No more messages. nextPollTimeoutMillis = -1; } // Process the quit message now that all pending messages have been handled. if (mQuitting) { dispose(); return null; } // 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. mBlocked = true; continue; } if (mPendingIdleHandlers == null) { mPendingIdleHandlers = new IdleHandler[Math.max(pendingIdleHandlerCount, 4)]; } mPendingIdleHandlers = mIdleHandlers.toArray(mPendingIdleHandlers); } // Run the idle handlers. // 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 boolean keep = false; try { keep = idler.queueIdle(); } catch (Throwable t) { Log.wtf(TAG, "IdleHandler threw exception", t); } if (!keep) { synchronized (this) { mIdleHandlers.remove(idler); } } } // Reset the idle handler count to 0 so we do not run them again. 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. nextPollTimeoutMillis = 0; } }