IdleHandler是什么?
看MessageQueue源码的时候发现一个IdleHandler,但它并不是Handler,直译过来的话应该叫“闲置处理器”。一般开发中不会用到,了解一下Android框架中的源码,以免以后有骚操作需要说不定会用上。
1、IdleHandler定义
IdleHandler是定义在MessageQueue类中的一个接口:
/**
* Callback interface for discovering when a thread is going to block
* waiting for more messages.
*/
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. This may be called if there are still messages
* pending in the queue, but they are all scheduled to be dispatched
* after the current time.
*/
boolean queueIdle();
}
从Android源码的注释我们可以初步看到这是一个闲置回调接口:
①当消息队列空闲阻塞等待更多消息时,回调该接口。可以在消息队列空闲时做一些操作,避开“UI主线程高峰期”。
②返回类型boolean值,为true时会保留该“闲置处理器”,下次消息队列闲置时仍然会回调(谨慎使用,控制好返回值,以免“蹩脚的程序员”无限调用)。返回false时,被调用后就会被移除。
③显然,queueIdle()方法在主线程不适宜执行耗时操作。
2、空闲
消息队列什么时候空闲呢?MessageQueue供了一个方法isIdle()判断当前消息队列是否空闲:
/**
* Returns true if the looper has no pending messages which are due to be processed.
*
* <p>This method is safe to call from any thread.
*
* @return True if the looper is idle.
*/
public boolean isIdle() {
synchronized (this) {
final long now = SystemClock.uptimeMillis();
return mMessages == null || now < mMessages.when;
}
}
从代码可以看出“空闲”的含义:当前没有Message,或者有Message但是延迟消息当前无需处理(没到时候)。
3、IdleHandler相关源码
MessageQueue类中与IdleHandler相关的代码只有三处:两个相关的变量定义、添加和移除“闲置处理器”的方法以及next()方法中。
3.1、内部变量
MessageQueue中定义了两个IdleHandler相关的成员变量:一个是用来保存添加到该消息队列中的IdleHandler集合mIdleHandlers;另一个是用在next()方法中的临时中转数组mPendingIdleHandlers:之所以这样做,因为还要修改原有集合mIdleHandlers,所以干脆拷贝一份数组副本。
@UnsupportedAppUsage
private final ArrayList<IdleHandler> mIdleHandlers = new ArrayList<IdleHandler>();
private IdleHandler[] mPendingIdleHandlers;
3.2、添加和移除方法
添加一个IdleHandler实例到消息队列MessageQueue中。一定不能为空,否则会抛出异常。
/**
* 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);
}
}
从添加到这个消息队列的IdleHandler集合中移除指定的“闲置处理器”:
/**
* Remove an {@link IdleHandler} from the queue that was previously added
* with {@link #addIdleHandler}. If the given object is not currently
* in the idle list, nothing is done.
*
* <p>This method is safe to call from any thread.
*
* @param handler The IdleHandler to be removed.
*/
public void removeIdleHandler(@NonNull IdleHandler handler) {
synchronized (this) {
mIdleHandlers.remove(handler);
}
}
3.3、next()代码片段
在Handler消息延迟原理一文中,我们知道Loop通过next()不断从消息队列中取出Message。next()方法中和IdleHandler相关的代码片段如下:
如果消息队列空闲,并且有需要处理的“闲置处理器”:先将mIdleHandlers转成数组存起来在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);
...
接下来就是遍历数组,执行接口方法queueIdle():返回false就会从mIdleHandlers中移除当前执行过的IdleHandler。
...
// 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();
} catch (Throwable t) {
Log.wtf(TAG, "IdleHandler threw exception", t);
}
if (!keep) {
synchronized (this) {
mIdleHandlers.remove(idler);
}
}
}
...