When MessageQueue
idle, IdleHandler
the method inside will be called, which can be used to start optimization, use idle time to load configuration, and avoid stuck UI display.
scenes to be used
1.Activity's life cycle callback #onStop and #onDestroy
2. Startup optimization (the engine of WebView is loaded in advance)
basic use
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
mainLooper.queue.addIdleHandler {
//加载闲时任务
false
}
}
The return value false
means that the task will only be executed once
The return value true
means that the task will be executed multiple times
principle
@UnsupportedAppUsage
private final ArrayList<IdleHandler> mIdleHandlers = new ArrayList<IdleHandler>();
@UnsupportedAppUsage
Message 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 iteration
int nextPollTimeoutMillis = 0;
for (;;) {
if (nextPollTimeoutMillis != 0) {
Binder.flushPendingCommands();
}
nativePollOnce(ptr, nextPollTimeoutMillis);
synchronized (this) {
...
// 如果第一次空闲,那么获取要运行的空闲程序的数量。
// 空闲句柄仅在队列为空或第一条消息时运行
// 在队列中(可能是一个同步屏障)是由于在将来被处理。
if (pendingIdleHandlerCount < 0
&& (mMessages == null || now < mMessages.when)) {
pendingIdleHandlerCount = mIdleHandlers.size();
}
if (pendingIdleHandlerCount <= 0) {
//没有空闲的处理程序可以运行。循环并等待更多时间。
mBlocked = true;
continue;
}
if (mPendingIdleHandlers == null) {
mPendingIdleHandlers = new IdleHandler[Math.max(pendingIdleHandlerCount, 4)];
}
mPendingIdleHandlers = mIdleHandlers.toArray(mPendingIdleHandlers);
}
// 运行空闲处理程序。
// 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;
}
}
When judging that the message queue currently has no messages, the tasks in mIdleHandlers will be executed
When the message queue is empty, will inserting a barrier trigger IdleHandler?
Answer: No, inserting a barrier will not wake up the thread
If the barrier is deleted and the message queue is empty, will the IdleHandler be triggered?
Answer: No. After processing the message, it is found that there is no message to process (or the trigger time has not arrived), trigger IdleHandler, and the processing is completed. It will check again whether there is a message to be processed, because when IdleHandler is triggered, a new message may be inserted into the message queue. If not, go to sleep, and when woken up again, the IdleHandler will not be (repeatedly) triggered again. Simply put, the message queue has processed the last message, called IdleHandler before hibernation, and is woken up after hibernation. There is still no message to be processed, and IdleHandler will not be called repeatedly
If the message queue has only one barrier message, will inserting a normal message trigger IdleHandler?
Answer: It is possible. The trigger condition of IdleHandler is that the message queue is empty, or the trigger time of the first message has not yet arrived. So if the timeout of the barrier has not yet expired, that is, there is no message to be processed yet, the IdleHandler will be triggered
If the message queue has only one barrier message, will inserting an asynchronous message trigger IdleHandler?
Answer: It is possible. The key depends on whether the trigger time of the barrier is up. If not, the IdleHandler will be triggered, otherwise it will not.
Precautions
1. Do not load time-consuming tasks
Time-consuming tasks will block the execution of other tasks
2. Don’t add too many tasks
When loading in idle time, all idle time tasks will be processed at one time, too long time will cause ANR
material
[1]. Do you know how to use IdleHandler? Remember a misunderstanding in the use of IdleHandler, which leads to ANR
[2]. You should know about the message barrier of Handler