介紹
IdleHandler 是 MessageQueue 內(nèi)定義的一個(gè)接口,一般可用于做性能優(yōu)化。當(dāng)消息隊(duì)列內(nèi)沒(méi)有需要立即執(zhí)行的 message 時(shí),會(huì)主動(dòng)觸發(fā) IdleHandler 的 queueIdle 方法。返回值為 false,即只會(huì)執(zhí)行一次;返回值為 true,即每次當(dāng)消息隊(duì)列內(nèi)沒(méi)有需要立即執(zhí)行的消息時(shí),都會(huì)觸發(fā)該方法。
public final class MessageQueue {
public static interface IdleHandler {
boolean queueIdle();
}
}
使用方式
通過(guò)獲取 looper 對(duì)應(yīng)的 MessageQueue 隊(duì)列注冊(cè)監(jiān)聽(tīng)。
Looper.myQueue().addIdleHandler(new MessageQueue.IdleHandler() {
@Override
public boolean queueIdle() {
// doSomething()
return false;
}
});
源碼解析
IdleHandler 的執(zhí)行源碼很短。
Message next() {
// 隱藏?zé)o關(guān)代碼...
int pendingIdleHandlerCount = -1; // -1 only during first iteration
int nextPollTimeoutMillis = 0;
for (; ; ) {
// 隱藏?zé)o關(guān)代碼...
// 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;
}
- 在
MessageQueue里next方法的for死循環(huán)內(nèi),獲取mIdleHandlers的數(shù)量pendingIdleHandlerCount; - 通過(guò)
mMessages == null || now < mMessages.when判斷當(dāng)前消息隊(duì)列為空或者目前沒(méi)有需要執(zhí)行的消息時(shí),給pendingIdleHandlerCount賦值; - 當(dāng)數(shù)量大于 0,遍歷取出數(shù)組內(nèi)的
IdleHandler,執(zhí)行queueIdle(); - 返回值為
false時(shí),主動(dòng)移除監(jiān)聽(tīng)mIdleHandlers.remove(idler);
使用場(chǎng)景
- 如果啟動(dòng)的
Activity、Fragment、Dialog內(nèi)含有大量數(shù)據(jù)和視圖的加載,導(dǎo)致首次打開(kāi)時(shí)動(dòng)畫切換卡頓或者一瞬間白屏,可將部分加載邏輯放到queueIdle()內(nèi)處理。例如引導(dǎo)圖的加載和彈窗提示等; - 系統(tǒng)源碼中
ActivityThread的GcIdler,在某些場(chǎng)景等待消息隊(duì)列暫時(shí)空閑時(shí)會(huì)嘗試執(zhí)行 GC 操作; - 系統(tǒng)源碼中
ActivityThread的Idler,在handleResumeActivity()方法內(nèi)會(huì)注冊(cè)Idler(),等待handleResumeActivity后視圖繪制完成,消息隊(duì)列暫時(shí)空閑時(shí)再調(diào)用AMS的activityIdle方法,檢查頁(yè)面的生命周期狀態(tài),觸發(fā)activity的stop生命周期等。
這也是為什么我們BActivity跳轉(zhuǎn)CActivity時(shí),BActivity生命周期的onStop()會(huì)在CActivity的onResume()后。 - 一些第三方框架
Glide和LeakCanary等也使用到IdleHandler,感興趣的朋友可以看看源碼;