IdleHandler是什么?​

QuibblerQuibbler 2021-01-19 约 13 分钟 1727 次阅读

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);
                    }
                }
            }
        ...

相关推荐

精选
ViewPager和PagerAdapter、FragmentPagerAdapter、FragmentStatePager
Android

ViewPager和PagerAdapter、FragmentPagerAdapter、FragmentStatePager

ViewPager1、ViewPagerandroidx.viewpager.widget.ViewPager,Android中使用非常广泛的控件,可以说是APP必备:首次打开引导页、页面Banner广告等。常用方法:setAdapter() 设置适配器setOffscreenPageLimit() 设置缓存的页面个数,默认是 1setCurrentItem() 跳转到特定的页面setOnPage

1.1k
获取Android内置WebView内核版本
Android

获取Android内置WebView内核版本

获取Android内置WebView内核版本竟然能遇到这样奇葩的事情,网页用的技术过于新颖,以至于只支持高版本Chromium内核的,低版本安卓系统中内置的内核版本较低,无法加载前端页面。1、设置查看在系统设置里 > 应用 > 应用管理 > 显示系统应用,查看WebView组件:2、页面查看通过WebView发起的网络请求,都会带上浏览器的UA,通常页面都可以通过UA判断浏览器的内核版本。这里有两

1.1w
Android 14适配总结
Android

Android 14适配总结

Android 14适配总结毕业工作至今已经适配了三个Android大版本,从Android 11到Android 12、再到Android 13。2023年,Google即将推出的Android 14,上半年已经开始第一批适配。现在,第四个Android版本已经适配完,总结记录一下。1、Android 14计划Google一般会在2月份对外发布预告,同时放出开发者预览版。“拉通”各大平台、厂商以

1.1w