介绍
IdleHandler 是 MessageQueue 内定义的一个接口,一般可用于做性能优化。当消息队列内没有需要立即执行的 message 时,会主动触发 IdleHandler 的 queueIdle 方法。返回值为 false,即只会执行一次;返回值为 true,即每次当消息队列内没有需要立即执行的消息时,都会触发该方法。
public final class MessageQueue {
public static interface IdleHandler {
boolean queueIdle();
}
}
复制代码
使用方式
通过获取 looper 对应的 MessageQueue 队列注册监听。
Looper.myQueue().addIdleHandler(new MessageQueue.IdleHandler() {
@Override
public boolean queueIdle() {
// doSomething()
return false;
}
});
复制代码
源码解析
IdleHandler 的执行源码很短。
Message next() {
// 隐藏无关代码...
int pendingIdleHandlerCount = -1; // -1 only during first iteration
int nextPollTimeoutMillis = 0;
for (; ; ) {
// 隐藏无关代码...
// 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死循环内,获取mIdleHandlers的数量pendingIdleHandlerCount; - 通过
mMessages == null || now < mMessages.when判断当前消息队列为空或者目前没有需要执行的消息时,给pendingIdleHandlerCount赋值; - 当数量大于 0,遍历取出数组内的
IdleHandler,执行queueIdle(); - 返回值为
false时,主动移除监听mIdleHandlers.remove(idler);
使用场景
- 如果启动的
Activity、Fragment、Dialog内含有大量数据和视图的加载,导致首次打开时动画切换卡顿或者一瞬间白屏,可将部分加载逻辑放到queueIdle()内处理。例如引导图的加载和弹窗提示等; - 系统源码中
ActivityThread的GcIdler,在某些场景等待消息队列暂时空闲时会尝试执行 GC 操作; - 系统源码中
ActivityThread的Idler,在handleResumeActivity()方法内会注册Idler(),等待handleResumeActivity后视图绘制完成,消息队列暂时空闲时再调用AMS的activityIdle方法,检查页面的生命周期状态,触发activity的stop生命周期等。这也是为什么我们BActivity跳转CActivity时,BActivity生命周期的onStop()会在CActivity的onResume()后。 - 一些第三方框架
Glide和LeakCanary等也使用到IdleHandler,感兴趣的朋友可以看看源码;
© 版权声明
文章版权归作者所有,未经允许请勿转载。
THE END



















![[02/27][官改] Simplicity@MIX2 ROM更新-一一网](https://www.proyy.com/wp-content/uploads/2020/02/3168457341.jpg)


![[桜井宁宁]COS和泉纱雾超可爱写真福利集-一一网](https://www.proyy.com/skycj/data/images/2020-12-13/4d3cf227a85d7e79f5d6b4efb6bde3e8.jpg)

![[桜井宁宁] 爆乳奶牛少女cos写真-一一网](https://www.proyy.com/skycj/data/images/2020-12-13/d40483e126fcf567894e89c65eaca655.jpg)