
面试官:“看你简历上写熟悉 Handler 机制,那聊聊 IdleHandler 吧?”
MessageQueue:基于消息的优先级队列,用于管理消息。 Looper:事件循环,负责不断从 MessageQueue 中取出消息进行处理。 Handler:接收并处理消息,定义在 MessageQueue 中。
MessageQueue 为空:无消息需处理。 延迟消息:下一条消息的时间晚于当前时间,需要滞后处理。
ActivityThread.Idler:用于Activity恢复。 GcIdler:内存不足时自动触发GARbage Collection。 Instrumentation.ActivityGoing:Activity启动前添加。 Instrumentation.Idler:用于键盘相关处理。 TextToSpeechService.SynthThread:TTS完成后发送广播。
发布日期:2021-05-14 19:19:22
浏览次数:11
分类:精选文章
本文共 3866 字,大约阅读时间需要 12 分钟。
Android Handler 中的 IdleHandler 详解
一. 序
Handler 机制是 Android 开发的基础知识,常见于面试中。如今,在面试中很少直接要求详细讲解 Handler 的机制,而是通过具体场景来测试候选人的理解深度。IdleHandler 因为相对少人使用,因此了解它的功能和使用场景尤为重要。
本文将深入探讨 Android Framework 中的 Handler 机制,特别是 IdleHandler 的功能、使用方法以及在开发中的适用场景。
二. IdleHandler 详解
2.1 简单介绍 Handler 机制
Handler 是 Android 中常用的事件驱动模型,核心由三部分组成:
注意: 早期,Handler 机制允许开发者自定义事件处理逻辑,消息循环由 Looper管理。
2.2 IdleHandler 是什么?如何使用?
IdleHandler 是 Handler 机制提供的一种在队列空闲时执行任务的额外功能。
2.2.1 IdleHandler 定义
IdleHandler 接口定义在 MessageQueue 中:
public static interface IdleHandler { boolean queueIdle();}
重要性:
- queueIdle():返回
true
表示是长期IdleHandler,会在下次空闲时重复执行;返回false
表示为一次性IdleHandler,只能运行一次。
2.2.2 使用方法
要使用IdleHandler,需在 MessageQueue 中添加和移除IdleHandler:
// MessageQueue.javapublic void addIdleHandler(@NonNull IdleHandler handler) { synchronized (this) { mIdleHandlers.add(handler); }}public void removeIdleHandler(@NonNull IdleHandler handler) { synchronized (this) { mIdleHandlers.remove(handler); }}
关键点:
-IdleHandler 在哪些场景下执行?队列空闲有两种状态:
2.3 IdleHandler 的执行机制
IdleHandler 的核心逻辑在 MessageQueue.next()
方法中:
Message next() { // ...其他逻辑... int pendingIdleHandlerCount = -1; int nextPollTimeoutMillis = 0; for (;;) { nativePollOnce(ptr, nextPollTimeoutMillis); synchronized (this) { // ...现有消息处理逻辑... // 如果有消息,处理,否则设置nextPollTimeoutMillis = -1; // 如果pendingIdleHandlerCount < 0,则获取mIdleHandlers.size(); // 如果mMessages为空或mMessages.when < now,则执行IdleHandler; if (pendingIdleHandlerCount < 0 && (mMessages == null || now < mMessages.when)) { pendingIdleHandlerCount = mIdleHandlers.size(); } // 如果pendingIdleHandlerCount <= 0,阻塞当前线程; if (pendingIdleHandlerCount <= 0) { mBlocked = true; continue; } // 将mIdleHandlers转换为数组处理; 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]; mPendingIdleHandlers[i] = null; // 执行队列超时逻辑; try { keep = idler.queueIdle(); } catch (Throwable t) { //日志处理... } // 如果keep 为false,移除该IdleHandler; if (!keep) { synchronized (this) { mIdleHandlers.remove(idler); } } } pendingIdleHandlerCount = 0; nextPollTimeoutMillis = 0; // 重置布置属性... } }}
- 关键点:
- pendingIdleHandlerCount 初始为-1,只在第一次循环中赋值。
- nextPollTimeoutMillis 设为0,阻止进入休眠状态。
- 当有多个IdleHandler执行时,每个都返回keep值。
- keep 为false 时,该IdleHandler 从mIdleHandlers中移除。
2.4框架中的使用场景
三. 常见面试问题解析
Q:IdleHandler 有什么用途?
- 用于在消息队列空闲时执行任务。
- 适用于需要在App休眠时进行操作,但不适合处理实时性要求高的任务。
Q:是否需要成对使用add/remove?
- 不是必须。返回值决定了是否移除IdleHandler。
Q:为什么不会进入死循环?
- 原因:
- pendingIdleHandlerCount 只执行一次。
- nextPollTimeoutMillis 设为0,不会因休眠进入死循环。
Q:能否将启动服务的任务放入IdleHandler?
- 不建议,因为时机不可控。如果消息队列忙碌,IdleHandler执行机会会很晚。
Q:IdleHandler 的执行线程是什么?
-由当前MessageQueue所属的Looper线程执行,可以在子线程构造Looper后使用。
四. 小结
IdleHandler 是Handler机制中的一个灵活工具,适用于需要在消息队列空闲时执行任务的场景。但其执行时机基于MessageQueue的状态,不可控,应用时需谨慎。
发表评论
最新留言
不错!
[***.144.177.141]2025年04月18日 02时29分22秒
关于作者

喝酒易醉,品茶养心,人生如梦,品茶悟道,何以解忧?唯有杜康!
-- 愿君每日到此一游!
推荐文章
vscode设置eslint保存文件时自动修复eslint错误
2019-03-11
deepin 安装过程记录
2019-03-11
JAVA 多线程
2019-03-11
Java的 arraylist类【具体案例】
2019-03-11
FileWriter
2019-03-11
删除DOM节点
2019-03-11
牛客-链表中环的入口节点(Java)
2019-03-11
【ARM自学笔记】ARM Cortex -A中断系统(程序篇)
2019-03-11
解决微信小程序中 calc 失效问题
2019-03-11
JS数组去重的方法
2019-03-11
堆的应用_topK算法和堆排序
2019-03-11
双向链表
2019-03-11
并查集(求连通块数量)
2019-03-11
最大半连通子图
2019-03-11
Remove Extra one 维护前缀最大最小值
2019-03-11
Mysql学习笔记
2019-03-11
跳台阶
2019-03-11
另类加法,走方格的方案数,最近公共祖先
2019-03-11
线程学习5
2019-03-11
[Java Path Finder][JPF学习笔记][7]JPF输出详细程度设置
2019-03-11