【Handler】IdleHandler

When MessageQueueidle, IdleHandlerthe 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)

booster ShadowWebView

basic use

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
    
    
    mainLooper.queue.addIdleHandler {
    
    
        //加载闲时任务
        false
    }
}

The return value falsemeans that the task will only be executed once
The return value truemeans 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

Guess you like

Origin blog.csdn.net/Android_yh/article/details/130611623