IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 移动开发 -> 关于空闲任务IdleHandler的那些事 -> 正文阅读

[移动开发]关于空闲任务IdleHandler的那些事

关于空闲任务IdleHandler的那些事

??Android的消息机制Handler已经是老生常谈了,包括Android Framework层的应用启动过程都涉及消息机制,肥柴在“一切从Android的Handler讲起”专栏中已经讲了很多。

??对于Android中的消息处理机制来说,MessageQueue和Looper、Message是非常重要的对象,而IdleHandler是MessageQueue的静态内部接口。那什么是IdleHandler呢?

带走

一、IdleHandler

??IdleHandler是一种在只有当消息队列没有消息或者是队列中的消息还没到执行时间时,才会执行的任务,其存放在MessageQueue的mIdleHandlers队列中。

    /** MessageQueue.class */
    /**
     * 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.
         */
        // 返回true,表示这个接口一直有效,下次cpu空闲时还会调用
        // 返回false,表示这个接口只会被调用一次,调用一次后从mIdleHandlers中移除
        boolean queueIdle();
    }

    public void addIdleHandler(@NonNull IdleHandler handler) {
        if (handler == null) {
            throw new NullPointerException("Can't add a null IdleHandler");
        }
        synchronized (this) {
            mIdleHandlers.add(handler);
        }
    }

??使用方式是实现IdleHandler接口,在queueIdle实现MessageQueue空闲时需要处理的逻辑,并通过addIdleHandler()方法添加到mIdleHandlers队列中。

    MessageQueue.IdleHandler idleHandler = new MessageQueue.IdleHandler() {
        @Override
        public boolean queueIdle() {
            // 空闲时处理逻辑

            return false;
        }
    };
    Looper.getMainLooper().getQueue().addIdleHandler(idleHandler);

嗯,然后呢?

二、IdleHandler实现基本原理

??知道了IdleHandler的定义和使用,那么Handler消息机制是如何实现MessageQueue空闲的时候调用IdleHandler进行任务处理的呢?这就需要我们从MessageQueue的next方法入手了,至于Looper消息的获取可以见肥柴之前的:一切从Android的Handler讲起(四):Looper消息获取一文。

    /** MessageQueue.class */
    @UnsupportedAppUsage
    Message next() {
        // ...

        int pendingIdleHandlerCount = -1; // -1 only during first iteration
        int nextPollTimeoutMillis = 0;
        for (;;) {
            if (nextPollTimeoutMillis != 0) {
                Binder.flushPendingCommands();
            }

            nativePollOnce(ptr, nextPollTimeoutMillis);

            synchronized (this) {
                // Try to retrieve the next message.  Return if found.
                final long now = SystemClock.uptimeMillis();
                Message prevMsg = null;
                Message msg = mMessages;
                // 注释1 屏障消息处理,获取异步消息
                if (msg != null && msg.target == null) {
                    // Stalled by a barrier.  Find the next asynchronous message in the queue.
                    do {
                        prevMsg = msg;
                        msg = msg.next;
                    } while (msg != null && !msg.isAsynchronous());
                }
                // 注释2 获取到Message不为null,则说明存在需要处理的Message
                if (msg != null) {
                    if (now < msg.when) {
                        // Next message is not ready.  Set a timeout to wake up when it is ready.
                        nextPollTimeoutMillis = (int) Math.min(msg.when - now, Integer.MAX_VALUE);
                    } else {
                        // Got a message.
                        mBlocked = false;
                        if (prevMsg != null) {
                            prevMsg.next = msg.next;
                        } else {
                            mMessages = msg.next;
                        }
                        msg.next = null;
                        if (DEBUG) Log.v(TAG, "Returning message: " + msg);
                        msg.markInUse();
                        return msg;
                    }
                } else {
                    // No more messages.
                    // MessageQueue无消息,设置延迟为-1,nativePollOnce无限等待,直到有消息
                    nextPollTimeoutMillis = -1;
                }

                // 注释3 执行到此处,说明没有需要执行的Message(MessageQueue为空,或者存在延迟Message)
                // Process the quit message now that all pending messages have been handled.
                if (mQuitting) {
                    dispose();
                    return null;
                }

                // 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();
                }
                // 注释4 IdleHandler队列为空,不执行,进入下一个循环,此后不再会执行IdleHandler判断,除非下次进入next方法
                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)];
                }
                // 注释5 mIdleHandlers数组赋值给 mPendingIdleHandlers
                mPendingIdleHandlers = mIdleHandlers.toArray(mPendingIdleHandlers);
            }

            // 注释6 执行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 {
                    // 注释7 执行任务逻辑,并返回任务释放移除
                    keep = idler.queueIdle();
                } catch (Throwable t) {
                    Log.wtf(TAG, "IdleHandler threw exception", t);
                }

                if (!keep) {
                    synchronized (this) {
                        // 注释8 移除任务,下次不再执行
                        mIdleHandlers.remove(idler);
                    }
                }
            }

            // 注释9 重置IdleHandler的Count为0,避免下次重复执行IdleHandler队列
            pendingIdleHandlerCount = 0;

            // While calling an idle handler, a new message could have been delivered
            // so go back and look again for a pending message without waiting.
            nextPollTimeoutMillis = 0;
        }
    }

??这里肥柴把源码里涉及到IdleHandler处理的进行了注释,重点看注释的地方即可,从而我们可以总结IdleHandler实现的基本原理流程:

??1、如果本次循环拿到的Message为空,或者这个Message是一个延时的消息而且还没到指定的触发时间,那么,就认定当前的队列为空闲状态

??2、遍历mPendingIdleHandlers数组(这个数组里面的元素每次都会到mIdleHandlers中去拿)来调用每一个IdleHandler实例的queueIdle方法

??3、如果这个方法返回false的话,那么这个实例就会从 mIdleHandlers 中移除,也就是当下次队列空闲的时候,不会继续回调它的 queueIdle 方法了。

??4、处理完 IdleHandler 后会将 nextPollTimeoutMillis 设置为0,也就是不阻塞消息队列,当然要注意这里执行的代码同样不能太耗时,因为它是同步执行,如果太耗时肯定会影响后面的 message 执行。

IdleHandler实现基本原理

三、使用场景

??根据IdleHandler的特性,其使用场景遵循一个基本原则:在不影响其他任务,在消息队列空闲状态下执行。

??Android Framework层的GC场景就使用了这个机制,只有当cpu空闲的时候才会去GC。

    void scheduleGcIdler() {
        if (!mGcIdlerScheduled) {
            mGcIdlerScheduled = true;
            Looper.myQueue().addIdleHandler(mGcIdler);
        }
        mH.removeMessages(H.GC_WHEN_IDLE);
    }

    final class GcIdler implements MessageQueue.IdleHandler {
        @Override
        public final boolean queueIdle() {
            doGcIfNeeded();
            return false;
        }
    }

??而我们熟知的内存泄漏检测库LeakCanary,其进行内存泄漏检测并不是 onDestry 方法执行完成后就进行垃圾回收和一些分析的,而是利用 IdleHandler 在空闲的时候进行这些操作的,尽量不去影响主线程的操作

闲

  移动开发 最新文章
Vue3装载axios和element-ui
android adb cmd
【xcode】Xcode常用快捷键与技巧
Android开发中的线程池使用
Java 和 Android 的 Base64
Android 测试文字编码格式
微信小程序支付
安卓权限记录
知乎之自动养号
【Android Jetpack】DataStore
上一篇文章      下一篇文章      查看所有文章
加:2022-05-18 17:46:02  更:2022-05-18 17:48:04 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/25 2:02:33-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码