IdleHandler的使用及原理 - 简书 (jianshu.com)
IdleHandler方式就是利用其特性,只有CPU空闲的时候才会执行相关任务,并且我们可以分批进行任务初始化,可以有效缓解界面的卡顿。
简单用法代码如下:
Looper.myQueue().addIdleHandler(object: MessageQueue.IdleHandler {
override fun queueIdle(): Boolean {
//执行任务
return false;
}
})
可以将上述代码添加到Activity onCreate中,在queueIdle()方法中实现延迟执行任务,在主线程空闲,也就是activity创建完成之后,它会执行queueIdle()方法中的代码。
如何设置是否重复执行
queueIdle()返回true表示可以反复执行该方法,即执行后还可以再次执行;返回false表示执行完该方法后会移除该IdleHandler,即只执行一次。
IdleHandler源码解析:
IdleHandler属于MessageQueue内部接口,只有一个queueIdle()方法声明。通过方法addIdleHandler将我们的idleHandler添加到集合中。
public final class MessageQueue {
private final ArrayList<IdleHandler> mIdleHandlers = new ArrayList<IdleHandler>();
/**
* 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);
}
}
/**
* Callback interface for discovering when a thread is going to block
* waiting for more messages.
*/
public static interface IdleHandler {
boolean queueIdle();
}
}
IdleHandler的queueIdle方法何时执行
在MessageQueue取消息的next方法中,IdleHandler相关代码如下:
@UnsupportedAppUsage
Message next() {
...
int pendingIdleHandlerCount = -1; // -1 only during first iteration
int nextPollTimeoutMillis = 0;
for (;;) {
if (nextPollTimeoutMillis != 0) {
Binder.flushPendingCommands();
}
nativePollOnce(ptr, nextPollTimeoutMillis);
synchronized (this) {
...
if (msg != 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)) {
//如果消息队列为空或者消息执行时间还未到,则获取IdleHandler队列的大小,下面需要用到
pendingIdleHandlerCount = mIdleHandlers.size();
}
if (pendingIdleHandlerCount <= 0) {
// No idle handlers to run. Loop and wait some more.
//无需要执行的 idle handler,则继续阻塞
mBlocked = true;
continue;
}
if (mPendingIdleHandlers == null) {
mPendingIdleHandlers = new IdleHandler[Math.max(pendingIdleHandlerCount, 4)];
}
//将IdleHandler列表转为数组
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(); //开始顺序执行所有IdleHandler的queueIdle方法
} catch (Throwable t) {
Log.wtf(TAG, "IdleHandler threw exception", t);
}
if (!keep) { //如果发现有queueIdle()方法返回false,则线程安全地删除这个idlehandler不再执行queueIdle
synchronized (this) {
mIdleHandlers.remove(idler);
}
}
}
...
}
}
多任务延迟初始化实战:
我们根据queueIdle返回true时可以执行多次的特点,可以实现一个任务列表,然后从这个任务列表中取任务执行。
public class TaskDispatcher {
private Queue<Runnable> delayTasks = new LinkedList<>();
private MessageQueue.IdleHandler idleHandler = () -> {
if (delayTasks.size() > 0) {
Runnable task = delayTasks.poll();
if (task != null) {
task.run();
}
}
return !delayTasks.isEmpty(); //只要task任务不为空,就继续执行初始化
};
public TaskDispatcher addTask(Runnable task) {
delayTasks.add(task);
return this;
}
public void start() {
Looper.myQueue().addIdleHandler(idleHandler);
}
}
创建一个ARouter初始化和Webview初始的task
public class WebviewInitTask implements Runnable {
@Override
public void run() {
Log.i("minfo", "初始化Okhttp");
}
}
public class WebviewInitTask implements Runnable {
@Override
public void run() {
Log.i("minfo", "初始化Webview");
}
}
界面显示后进行调用:
override fun onCreate(savedInstanceState: Bundle?) {
setTheme(R.style.AppTheme)
super.onCreate(savedInstanceState)
TaskDispatcher()
.addTask(ARouterInitTask())
.addTask(WebviewInitTask())
.start()
}
打印执行结果
关于IdleHandler问题
Q:IdleHandler 有什么用?
IdleHandler 是 Handler 提供的一种在消息队列空闲时,执行任务的时机;
当 MessageQueue 当前没有立即需要处理的消息时,会执行 IdleHandler;
Q:MessageQueue 提供了 add/remove IdleHandler 的方法,是否需要成对使用?
不是必须;
IdleHandler.queueIdle() 的返回值,可以移除加入 MessageQueue 的 IdleHandler;
Q:当 mIdleHanders 一直不为空时,为什么不会进入死循环?
只有在 pendingIdleHandlerCount 为 -1 时,才会尝试执行 mIdleHander;
pendingIdlehanderCount 在 next() 中初始时为 -1,执行一遍后被置为 0,所以不会重复执行;
Q:是否可以将一些不重要的启动服务,搬移到 IdleHandler 中去处理?
不建议;
IdleHandler 的处理时机不可控,如果 MessageQueue 一直有待处理的消息,那么 IdleHander 的执行时机会很靠后;
Q:IdleHandler 的 queueIdle() 运行在那个线程?
陷进问题,queueIdle() 运行的线程,只和当前 MessageQueue 的 Looper 所在的线程有关;
子线程一样可以构造 Looper,并添加 IdleHandler;
参考:
标签:task,IdleHandler,MessageQueue,queueIdle,使用,原理,执行,public From: https://www.cnblogs.com/wanglongjiang/p/17878825.html