Android MessageQueue has a static interface called IdleHandler. This interface is used to call back when there is no Message to handle in the UI thread. Call back some extra operations without blocking the UI thread (for example, if the UI thread is idle after the display is complete, we can prepare other content in advance), but it is best not to do time-consuming operations.
Specific usage:
mHandler.getLooper().getQueue().addIdleHandler(new MessageQueue.IdleHandler() {
@Override
public boolean queueIdle() {
// Do something relatively time-consuming
return false;
}
})
Mhandler.getlooper ().getQueue() can be replaced
GetMainLooper (). MyQueue () or the stars. The myQueue ()
Copy the code
Source code note:
/ * *
MyQueue (); getMainLooper().myQueue();
* /
public final class MessageQueue {
.
/ * *
* This interface callback is called when the current queue will be blocked waiting for messages, i.e. the queue is idle
* /
public static interface IdleHandler {
/ * *
* Return true if the method is not deleted after a single callback, and the next time it is idle, false if the method is called once.
* /
boolean queueIdle();
}
/ * *
* <p>This method is safe to call from any thread.
* The auxiliary method to determine whether the current queue is free
* /
public boolean isIdle() {
synchronized (this) {
final long now = SystemClock.uptimeMillis();
return mMessages == null || now < mMessages.when;
}
}
/ * *
* <p>This method is safe to call from any thread.
* Add an IdleHandler to the queue. If the IdleHandler interface returns false, it will be deleted automatically.
* Otherwise manually removeIdleHandler is required.
* /
public void addIdleHandler(@NonNull IdleHandler handler) {
if (handler == null) {
throw new NullPointerException("Can't add a null IdleHandler");
}
synchronized (this) {
mIdleHandlers.add(handler);
}
}
/ * *
* <p>This method is safe to call from any thread.
* Remove a previously added IdleHandler.
* /
public void removeIdleHandler(@NonNull IdleHandler handler) {
synchronized (this) {
mIdleHandlers.remove(handler);
}
}
.
//Looper's prepare() method prepares the MessageQueue instance of the current thread via ThreadLocal,
// Then call the next() method of the current queue in an infinite loop in the loop() method to get Message.
Message next() {
.
for (;;) {
.
nativePollOnce(ptr, nextPollTimeoutMillis);
synchronized (this) {
.
// Add idleHandlers to addIdleHandler as an array and store them in mPendingIdleHandlers
// 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.
// Loop through all idleHandlers
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 {
// Call queueIdle of the IdleHandler interface and get the return value.
keep = idler.queueIdle();
} catch (Throwable t) {
Log.wtf(TAG, "IdleHandler threw exception", t);
}
// if the queueIdle method of the IdleHandler interface returns false, delete the queueIdle method only once.
if (! keep) {
synchronized (this) {
mIdleHandlers.remove(idler);
}
}
}
.
}
}
}
Copy the code
Final thoughts:
Following this idea, we can consider optimizing the start speed of the Activity interface. Since onResume is called before drawing the interface, don’t ask why, look at the source code to know, hey, hey, so, Remove unnecessary events that are called before and before onResume (such as drawing certain interface views) and find a time to call them (after drawing). That should shorten the startup time. But there was no significant change in what they did overall. So what is the timing?
The IdleHandler is called when the looper message is finished. The IdleHandler is called when the onResume call is finished. The obvious IdleHandler is called after onResume and performTraversals have been drawn. In this way, I transferred some interface drawing logic in my page to IdleHandler, such as drawing loading of custom view, binding of adapter and initialization of other POP or dialog, which greatly reduced the time to open the interface without affecting the use.
Okay, move your cute fingers and optimize the code!
Like to pay attention to it, welcome to contribute, exchange!