听到公司前辈在电话面试时给别人提了个问题:“你了解IdleHandler吗?”噫,噫,噫。我之前对Android 的Handler工作流程梳理中没注意这个IdleHandler!!!潜意识中我感觉这个还是应该要去了解一下的;那我们今天就与源码中看看这个IdleHandler。这个IdleHandler并不直接在Handler中,而是在MessageQueue中定义的;
Idlehandler定义
/frameworks/base/core/java/android/os/MessageQueue.java
/**
* 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();
}
这个接口可以在线程将要进入阻塞状态等待更多的消息唤醒时回调,IdleHandler的接口的内部有个queueIdle()方法;这个方法是在消息队列已经取出所有的消息后等待等多的消息时被调用,如果返回true,则表示保持你的Idle Handler 继续存活;如果返回false就需要移除你的idle Handler;它也有可能在当前消息对了一层存在消息时被调用,但是这些消息是正要被分发处理的。
总而言之,就是在线程空闲或者即将空闲的时候会被调用,idle本身的词意也就是空闲的意思。
IdleHandler使用
我是没有在实际开发中使用过IdleHandler.所以一开始听过这个Idlehandler时也会很陌生的,那就更得要依赖于Android源码去了解,于是我就通过idle关键字搜索关于IdleHandler的使用情况,发现idleHandler的使用和Handler类似,也是需要先在MessageQueue中添加这个IdleHandler;然后再Looper的loop循环中取出idleHandler,接着就会处理Idlehandler了:
创建 idlerHandelr
在Activity启动时,有个GcIdler,我们就针对这个GcIdler来看看IdleHandler怎么使用的:
final class GcIdler implements MessageQueue.IdleHandler {
@Override
public final boolean queueIdle() {
doGcIfNeeded();
return false;
}
}
这个GcIdler实现了MessageQueue.Idlehandler,实现了queueIdle()方法,在IdleHandler 被调用的话就会执行在queueIdle()中的代码了。这里的是doGcidNeeded(),这就是这个GcIdler要做的任务;如果我们需要做其他的任务,在queueIdle()方法内添加其他的任务就行。
将IdleHandler添加到MessageQueue中
现在我们已经创建好了GcIdler,那接下来就需要把GcIdler添加到MessageQueue中去;我们看看Android系统是怎么将GcIdler添加到MessageQueue中去的
void scheduleGcIdler() {
if (!mGcIdlerScheduled) {
mGcIdlerScheduled = true;
Looper.myQueue().addIdleHandler(mGcIdler);
}
...
}
我们看到,将Gcidler添加到MessageQueue中的操作很见到,就是直接调用MessageQueue的addIdlerHandler()方法;接下来我们看看addIdlerHandler()方法是怎么添加的:
public void addIdleHandler(@NonNull IdleHandler handler) {
if (handler == null) {
throw new NullPointerException("Can't add a null IdleHandler");
}
synchronized (this) {
mIdleHandlers.add(handler);
}
}
在MessageQueue的addIdlehandler()方法中,直接是调用了mIdleHandler的add()方法;那么这mIdleHandler是个啥?
private final ArrayList<IdleHandler> mIdleHandlers = new ArrayList<IdleHandler>();
原来这个mIdlerHandler是个装有idleHandler的数组,这下就明白了,原来MessageQueue中有个专门保存Idlerhandler 的数组;
处理IdlerHandler
我们现在已经知道怎么将创建的IdleHandler添加到MessageQueue的IdlerHandler数组中,那接下来就需要关注Android是怎么处理IdlerHandler的:
Message next() {
...
for (;;) {
if (nextPollTimeoutMillis != 0) {
Binder.flushPendingCommands();
}
...
nativePollOnce(ptr, nextPollTimeoutMillis);
synchronized (this) {
...
if (msg != null) {
//处理Message
} else {
// No more messages.
nextPollTimeoutMillis = -1;
}
// 当Message为空时,就会来处理idleHandler
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);
}
...
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);
}
}
}
...
}
在MessageQueue中的next()方法中,我们看到就是在读取MessageQueue中的message ,当Message 为空时就会来处理IdleHandler。这个mPendingIdleHandlers就是我们的IdleHandler数组,主要我们看遍历IdleHandler数组这块:
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);
}
}
我们获取到一个IdleHandler后,就会调用它的queueIdle()方法,进而去处理在IdlerHandler中定义的任务,不同的IdleHandler的任务是不同的,我们在使用IdleHandler时就可以创建自己的任务。这里就不细说,我们只要关注一下queueIdle()的返回值,如果返回的是false,就会将当前Idlehandler移除。
小结
Idlehandler一般都是在线程空闲的时候被调用,所有经常被用来进行应用的优化,我目前开发经验很少,没有在项目中实际使用过,但是我们可以从源码的梳理中,明白IdleHandler的工作流程,对以后的工作相信会提供更多的便利。这也是我梳理源码的一个主要原因。