关于作者:CSDN内容合伙人、技术专家, 从零开始做日活千万级APP。
专注于分享各领域原创系列文章 ,擅长java后端、移动开发、人工智能等,希望大家多多支持。
一、导读
我们继续总结学习Android 基础知识,温故知新。
二、概览
IdleHandler 是 Handler 提供的一种充分利用CPU的机制, 主要是在 MessageQueue 出现空闲的时候被执行,
运行在Looper 所在的线程中,队列出现空闲存在两种场景:
- 循环拿到的Message为空
- 这个Message是一个延时的消息;
另外由于IdleHandler 的处理时机不可控,如果 MessageQueue 一直有待处理的消息,那么 IdleHander 的执行时机会很靠后,
所以需要根据具体业务来决定是否使用这样的延迟加载。
三、使用
使用起来非常简单,几行代码即可
protected void initIdleHandler() {
MessageQueue.IdleHandler() idleHandler = new MessageQueue.IdleHandler() {
@Override
public boolean queueIdle() {
// TODO: 2023/7/21
return true; 当消息队列内没有需要立即执行的消息时,都会触发该方法
return false;即只会执行一次;
}
};
Looper.myQueue().addIdleHandler(idleHandler);
}
手动移除
Looper.myQueue().removeIdleHandler(idleHandler);
3.1 使用场景
主要用于在消息队列空闲的时候处理一些轻量级的工作,
在不影响其他任务,在消息队列空闲状态下执行,如加载图片,延迟初始化,Android Framework层的GC 等
四、原理
IdleHandler看起来好像是个Handler,但他其实只是一个有单方法的接口,是MessageQueue静态内部接口。
返回值为 false,即只会执行一次;
返回值为 true,即每次当消息队列内没有需要立即执行的消息时,都会触发该方法。
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.
*
*/
boolean queueIdle();
}
在MessageQueue中有一个List存储了IdleHandler对象,当MessageQueue没有需要被执行的MessageQueue时就会遍历回调所有的IdleHandler。
其处理逻辑在 MessageQueue.java 的next方法中,如下:
Message next() {
......
死循环
for (;;) {
if (nextPollTimeoutMillis != 0) {
Binder.flushPendingCommands();
}
//1.阻塞函数
nativePollOnce(ptr, nextPollTimeoutMillis);
//2.从链表里面取出消息
......
//3.开始处理IdelHandler
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);
}
// 执行IdleHandler队列中的空闲任务
for (int i = 0; i < pendingIdleHandlerCount; i++) {
final IdleHandler idler = mPendingIdleHandlers[i];
try {
keep = idler.queueIdle();
} catch (Throwable t) {
}
//4.如果keep为false,则就从列表当中去除
if (!keep) {
synchronized (this) {
mIdleHandlers.remove(idler);
}
}
}
...
}
}
如果循环拿到的Message为空,或者这个Message是一个延时的消息,也即当前没有可执行Message,则认为是一个空闲,
这时就开始遍历mIdleHandlers数组, 使用临时数组来保存当前要执行的消息,循环中从数组中取出 IdleHandler,并调用其 queueIdle() 方法。
其流程也并不复杂,我借用一张网络图
public void addIdleHandler(@NonNull IdleHandler handler) {
if (handler == null) {
throw new NullPointerException("Can't add a null IdleHandler");
}
synchronized (this) {
mIdleHandlers.add(handler); //mIdleHandlers是一个ArrayList
}
}