IdleHandler是什么?​

Quibbler 2021-1-19 610

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()不断从消息队列中取出Messagenext()方法中和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);
                    }
                }
            }
        ...



不忘初心的阿甘
最新回复 (0)
    • 安卓笔记本
      2
        登录 注册 QQ
返回
仅供学习交流,切勿用于商业用途。如有错误欢迎指出:fluent0418@gmail.com