问:什么是 IdleHandler?有什么用?怎么用?
答:IdleHandler 可以用来提升性能,主要用在我们希望能够在当前线程消息队列空闲时做些事情(譬如 UI 线程在显示完成后,如果线程空闲我们就可以提前准备其他内容)的情况下,不过最好不要做耗时操作。具体用法如下。
//getMainLooper().myQueue()或者Looper.myQueue() Looper.myQueue().addIdleHandler(new IdleHandler() { @Override public boolean queueIdle() { //你要处理的事情 return false; } });
关于 IdleHandler 在 MessageQueue 与 Looper 和 Handler 的关系原理源码分析如下
/** * 获取当前线程队列使用Looper.myQueue(),获取主线程队列可用getMainLooper().myQueue() */ public final class MessageQueue { ...... /** * 当前队列将进入阻塞等待消息时调用该接口回调,即队列空闲 */ public static interface IdleHandler { /** * 返回true就是单次回调后不删除,下次进入空闲时继续回调该方法,false只回调单次。 */ boolean queueIdle(); } /** * <p>This method is safe to call from any thread. * 判断当前队列是不是空闲的,辅助方法 */ 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. * 添加一个IdleHandler到队列,如果IdleHandler接口方法返回false则执行完会自动删除, * 否则需要手动removeIdleHandler。 */ 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. * 删除一个之前添加的 IdleHandler。 */ public void removeIdleHandler(@NonNull IdleHandler handler) { synchronized (this) { mIdleHandlers.remove(handler); } } ...... //Looper的prepare()方法会通过ThreadLocal准备当前线程的MessageQueue实例, //然后在loop()方法中死循环调用当前队列的next()方法获取Message。 Message next() { ...... for (;;) { ...... nativePollOnce(ptr, nextPollTimeoutMillis); synchronized (this) { ...... //把通过addIdleHandler添加的IdleHandler转成数组存起来在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. //循环遍历所有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 { //调用IdleHandler接口的queueIdle方法并获取返回值。 keep = idler.queueIdle(); } catch (Throwable t) { Log.wtf(TAG, "IdleHandler threw exception", t); } //如果IdleHandler接口的queueIdle方法返回false说明只执行一次需要删除。 if (!keep) { synchronized (this) { mIdleHandlers.remove(idler); } } } ...... } } }