【Android 异步操作】Handler 机制 ( MessageQueue 空闲任务 IdleHandler 机制 )
文章目錄
- 一、MessageQueue 空閑任務 IdleHandler 機制
- 二、MessageQueue 中空閑任務 IdleHandler 相關源碼
一、MessageQueue 空閑任務 IdleHandler 機制
在 消息隊列 MessageQueue 的 next 獲取下一條消息的方法中 ,
在循環獲取消息的最后有如下代碼 :
public final class MessageQueue {@UnsupportedAppUsageMessage next() {// ...// 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)) {// 如果取出的 消息為空 , 就會執行 IdleHandlerpendingIdleHandlerCount = 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);// ...} }開始判定 pendingIdleHandlerCount 大小 , 如果小于 000 則執行后續 與 IdleHandler 相關操作 ;
IdleHandler 是一個 接口 , 代碼如下 :
public final class MessageQueue {/*** 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.*/boolean queueIdle();} }在上述如果取出的 mMessage 消息為空 mMessages == null , 則執行 IdleHandler ;
IdleHandler 使用時 , 調用 addIdleHandler 函數 , 該函數會將 IdleHandler 加入到 mIdleHandlers 集合中 ,
MessageQueue 消息隊列 addIdleHandler 函數如下 :
public final class MessageQueue {/*** 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}.** <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);}} }在 MessageQueue 的 next 方法中繼續向下執行 , 開始遍歷 mIdleHandlers 集合 , 先將集合 mIdleHandlers 轉為 mPendingIdleHandlers 數組 , 然后遍歷該數組 ,
遍歷時 , 調用 IdleHandler 對象的 queueIdle 方法 ,
如果上面的 queueIdle 方法返回值是 false , 就會從 mIdleHandlers 集合中 移除該元素 ,
如果上面的 queueIdle 方法返回值是 true , 那么下一次再次執行到這里時 , 還會 繼續回調該函數 ;
上述操作對應的 MessageQueue 的 next 方法內的部分源碼 :
public final class MessageQueue {@UnsupportedAppUsageMessage next() {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 handlerboolean 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;} }IdleHandler 的作用是 , 當消息隊列 MessageQueue 中沒有消息處理時 , 處于閑置狀態時 , 此時就會回調一次用戶注冊的 IdleHandler ,
如果該 IdleHandler 的 queueIdle 方法返回 false , 那么該 IdleHandler 只會 執行一次 ,
如果該 IdleHandler 的 queueIdle 方法返回 true , 則 每次空閑 , 都要執行一次該 IdleHandler ;
二、MessageQueue 中空閑任務 IdleHandler 相關源碼
public final class MessageQueue {@UnsupportedAppUsageMessage mMessages;@UnsupportedAppUsageprivate final ArrayList<IdleHandler> mIdleHandlers = new ArrayList<IdleHandler>();private IdleHandler[] mPendingIdleHandlers;@UnsupportedAppUsageMessage 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 iterationint 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)) {// 如果取出的 消息為空 , 就會執行 IdleHandlerpendingIdleHandlerCount = 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 handlerboolean 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;}}/*** 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.*/boolean queueIdle();}}
總結
以上是生活随笔為你收集整理的【Android 异步操作】Handler 机制 ( MessageQueue 空闲任务 IdleHandler 机制 )的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 【Android 异步操作】Handle
- 下一篇: 【Android 异步操作】Handle