深入了解IdleHandler,用来做优化或者轻量级任务都是极好的

简介: IdleHandler 是 Handler 提供的一种充分利用CPU的机制, 主要是在 MessageQueue 出现空闲的时候被执行
关于作者:CSDN内容合伙人、技术专家, 从零开始做日活千万级APP。
专注于分享各领域原创系列文章 ,擅长java后端、移动开发、人工智能等,希望大家多多支持。

在这里插入图片描述

一、导读

我们继续总结学习Android 基础知识,温故知新。

二、概览

IdleHandler 是 Handler 提供的一种充分利用CPU的机制, 主要是在 MessageQueue 出现空闲的时候被执行,
运行在Looper 所在的线程中,队列出现空闲存在两种场景:

  • 循环拿到的Message为空
  • 这个Message是一个延时的消息;

另外由于IdleHandler 的处理时机不可控,如果 MessageQueue 一直有待处理的消息,那么 IdleHander 的执行时机会很靠后,
所以需要根据具体业务来决定是否使用这样的延迟加载。

三、使用

使用起来非常简单,几行代码即可

    protected void initIdleHandler() {
        MessageQueue.IdleHandler() idleHandler = new MessageQueue.IdleHandler() {
            @Override
            public boolean queueIdle() {
                // TODO: 2023/7/21  
                return true; 当消息队列内没有需要立即执行的消息时,都会触发该方法
                return false;即只会执行一次;
            }
        };
        Looper.myQueue().addIdleHandler(idleHandler);
    }

    手动移除
    Looper.myQueue().removeIdleHandler(idleHandler);
        

3.1 使用场景

主要用于在消息队列空闲的时候处理一些轻量级的工作,
在不影响其他任务,在消息队列空闲状态下执行,如加载图片,延迟初始化,Android Framework层的GC 等

四、原理

IdleHandler看起来好像是个Handler,但他其实只是一个有单方法的接口,是MessageQueue静态内部接口。

    返回值为 false,即只会执行一次;
    返回值为 true,即每次当消息队列内没有需要立即执行的消息时,都会触发该方法。

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

在MessageQueue中有一个List存储了IdleHandler对象,当MessageQueue没有需要被执行的MessageQueue时就会遍历回调所有的IdleHandler。
其处理逻辑在 MessageQueue.java 的next方法中,如下:

Message next() {
    ......
    死循环
    for (;;) {
        if (nextPollTimeoutMillis != 0) {
            Binder.flushPendingCommands();
        }
        //1.阻塞函数
        nativePollOnce(ptr, nextPollTimeoutMillis);
        //2.从链表里面取出消息
        ......
            //3.开始处理IdelHandler
            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);
        }


        // 执行IdleHandler队列中的空闲任务
        for (int i = 0; i < pendingIdleHandlerCount; i++) {
            final IdleHandler idler = mPendingIdleHandlers[i];
            try {
                keep = idler.queueIdle();
            } catch (Throwable t) {
            }
            
            //4.如果keep为false,则就从列表当中去除
            if (!keep) {
                synchronized (this) {
                    mIdleHandlers.remove(idler);
                }
            }
        }
        

        ...
    }
}

如果循环拿到的Message为空,或者这个Message是一个延时的消息,也即当前没有可执行Message,则认为是一个空闲,
这时就开始遍历mIdleHandlers数组, 使用临时数组来保存当前要执行的消息,循环中从数组中取出 IdleHandler,并调用其 queueIdle() 方法。

其流程也并不复杂,我借用一张网络图
在这里插入图片描述

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

相关文章
|
安全 Java 编译器
kotlin面试题
kotlin面试题
1208 1
|
机器学习/深度学习 人工智能 算法
【乐器识别系统】图像识别+人工智能+深度学习+Python+TensorFlow+卷积神经网络+模型训练
乐器识别系统。使用Python为主要编程语言,基于人工智能框架库TensorFlow搭建ResNet50卷积神经网络算法,通过对30种乐器('迪吉里杜管', '铃鼓', '木琴', '手风琴', '阿尔卑斯号角', '风笛', '班卓琴', '邦戈鼓', '卡萨巴', '响板', '单簧管', '古钢琴', '手风琴(六角形)', '鼓', '扬琴', '长笛', '刮瓜', '吉他', '口琴', '竖琴', '沙槌', '陶笛', '钢琴', '萨克斯管', '锡塔尔琴', '钢鼓', '长号', '小号', '大号', '小提琴')的图像数据集进行训练,得到一个训练精度较高的模型,并将其
617 0
【乐器识别系统】图像识别+人工智能+深度学习+Python+TensorFlow+卷积神经网络+模型训练
|
12月前
|
XML Java API
Android翻转动画(卡片翻转效果)
本文介绍了如何实现卡片翻转动画效果,通过Android中的ObjectAnimator结合不同插值器(LinearInterpolator、AccelerateInterpolator、DecelerateInterpolator)完成平滑过渡。示例中以按钮点击触发动画,核心逻辑包括判断视图可见性、设置旋转角度及处理初始Bug(如第一次点击异常)。最终提供完整代码(Java与XML布局),并指出将按钮事件替换为屏幕监听即可满足右滑触发需求。适合初学者学习动画实现原理。
439 0
|
存储 安全 数据安全/隐私保护
企业如何搭建技术支持体系?盘点三个需重点关注的方面
随着企业业务规模扩大,售后技术支持压力上升,构建高效专业的远程技术支持体系至关重要。向日葵技术支持方案从三个方面助力企业:1. 远控工具高效安全,提升客户体验;2. 自动化工单平台,优化需求流转;3. 客户信息管理,确保数据安全与追溯。向日葵凭借高效的产品设计、智能工单系统和完善的客户资料管理,帮助企业建立专业、可靠的售后服务体系。
455 0
|
ARouter IDE 开发工具
Android面试题之App的启动流程和启动速度优化
App启动流程概括: 当用户点击App图标,Launcher通过Binder IPC请求system_server启动Activity。system_server指示Zygote fork新进程,接着App进程向system_server申请启动Activity。经过Binder通信,Activity创建并回调生命周期方法。启动状态分为冷启动、温启动和热启动,其中冷启动耗时最长。优化技巧包括异步初始化、避免主线程I/O、类加载优化和简化布局。
505 3
Android面试题之App的启动流程和启动速度优化
|
Ubuntu Android开发
安卓系统调试与优化:(一)bootchart 的配置和使用
本文介绍了如何在安卓系统中配置和使用bootchart工具来分析系统启动时间,包括安装工具、设备端启用bootchart、PC端解析数据及分析结果的详细步骤。
1339 0
安卓系统调试与优化:(一)bootchart 的配置和使用
|
存储 大数据 数据库
Android经典面试题之Intent传递数据大小为什么限制是1M?
在 Android 中,使用 Intent 传递数据时存在约 1MB 的大小限制,这是由于 Binder 机制的事务缓冲区限制、Intent 的设计初衷以及内存消耗和性能问题所致。推荐使用文件存储、SharedPreferences、数据库存储或 ContentProvider 等方式传递大数据。
870 0
|
JavaScript 前端开发 编译器
Vue 源码学习路线
【4月更文挑战第20天】探索Vue源码涉及响应式系统、虚拟DOM、模板编译等核心概念。先掌握Vue基础知识、JavaScript(ES6+)和前端工程化。从源码入口文件开始,研究响应式、虚拟DOM、模板编译、实例方法、全局API及生命周期。理解编译器和渲染器工作原理,实践编写Vue插件,参与开源项目,阅读相关文章教程,持续关注Vue最新动态。这是一个循序渐进、需要耐心和实践的过程。
307 1