Android

[Android] Handler中的IdleHandler

2019-07-25  本文已影响2人  Merbng

抛出

Handler中的IdleHandler

Answer1:

首先看下源码的注释

/**
     * 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();
    }

注释中明确的指出当消息队列空闲时会执行IdelHandlerqueueIdle()方法,该方法返回一个boolean值,
如果为false则执行完毕之后移除这条消息,
如果为true则保留,等到下次空闲时会再次执行,

下面看下MessageQueuenext()方法可以发现确实是这样。

Message next() {
        ......
        for (;;) {
            ......
            synchronized (this) {
        // 此处为正常消息队列的处理
                ......
                if (mQuitting) {
                    dispose();
                    return null;
                }
                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);
                    }
                }
            }
            pendingIdleHandlerCount = 0;
            nextPollTimeoutMillis = 0;

        }
    }

处理完IdleHandler后会将nextPollTimeoutMillis设置为0,也就是不阻塞消息队列, 当然要注意这里执行的代码同样不能太耗时,因为它是同步执行的,如果太耗时肯定会影响后面的message执行。
能力大概就是上面讲的这样,那么能力决定用处,用处从本质上讲就是趁着消息队列空闲的时候干点事情,当然具体用处还是要看具体的处理。
要使用IdleHandler只需要调用MessageQueue#addIdleHandler(IdleHandler handler)方法即可

合适场景可以从下面几点出发:

目前可以想到的场景:
1.Activity启动优化:onCreate,onStart,onResume中耗时较短但非必要的代码可以放到IdleHandler中执行,减少启动时间
2.想要一个View绘制完成之后添加其他依赖于这个ViewView,当然这个View#post()也能实现,区别就是前者会在消息队列空闲时执行。
3.发生一个返回trueIdleHandler,在里面让某个View不停闪烁,这样当用户发呆时就可以诱导用户点击这个View,这也是种很酷的操作。
4.一些第三方库中使用,比如LeakCanary,Glide中使用到,具体可以自行去查看。

Answer2:

这个IdleHandler,它是声明在MessageQueue里面的一个接口,所以我们可以猜想到它跟MessageQueue一定有关系,这个接口只有一个方法:queueIdle,字面意思就是队列空闲。
MessageQueue的源码可以发现有两处关于IdleHandler的声明,分别是:

后面的数组,它里面放的IdleHandler实例都是临时的,也就是每次使用完(调用了queueIdle方法)之后,都会置空(mPendingIdleHandlers[i]=null)
那它们会在什么时候用到呢?
就是在MessageQueuenext方法里面
大概流程是这样的:
1.如果本次循环拿到的Message为空,或者!这个Message是一个延时的消息而且还没到指定触发时间,那么就认定当前的队列为空闲时间。
2.接着会遍历mPendingIdleHandlers数组(这个数组里面的元素每次都会到mIdleHandlers中去拿)来调用每一个IdleHandler实例的queueIdle方法。
3.如果这个方法返回false的话,那么这个实例就会从mIdleHandlers中移除,也就是当下次队列空闲的时候,不会继续回调它的queueIdle方法了。
来看看它在源码里的使用场景:
比如在ActivityThread中,就有一个名叫GcIdler的内部类,实现了IdleHandler接口。
它在queueIdle方法被回调时,会做强行GC的操作(即调用BinderInternalfaceGc方法),但强行GC的前提是与上一次强行GC至少相隔5秒以上。
那这个GcIdler会在什么时候使用呢?
ActivityThreadmH(Handler)收到GC_WHEN_IDLE消息之后。
何时会收到GC_WHEN_IDLE消息?
AMS(ActivityManagerService)中的这两个方法被调用之后:

Answer3:

IdleHandler:空闲监听器(就好像我没事做了,在群里发了个表情,这时候其他人就知道我很闲了)
在每次next获取消息进行处理时,发现没得可以处理的消息(队列空,只有延时消息并且没到时间,同步阻塞时没有异步消息)都会通知这些订阅者。

适合做一些可有可无的东西,因为这个通知太不稳定了(就像别人说过几天请你吃饭,你要真傻等着估计能饿死)

Answer4:

去看了MessageQueuenext方法的源码,是在MessageQueue空闲(当MQ中Message消息全部执行完毕或者处理一个延时消息)时调用。

系统还在这几个地方应用了:

  1. Activity onResume 以及view初始化完成之后调用
  2. 强行GC,当内存不足时调用
  3. TTS合成之后发生广播
  4. Activity onCreate()执行前添加
  5. 在键盘相关调用

结合系统的使用场景,推测一下,可以做UI操作,不能太耗时,调用的时机比较模糊关联性不能太强。

参考链接:
每日一问 听说过Handler中的IdleHandler吗?

上一篇 下一篇

猜你喜欢

热点阅读