博客
关于我
面试官:“看你简历上写熟悉 Handler 机制,那聊聊 IdleHandler 吧?”
阅读量:581 次
发布时间:2019-03-11

本文共 3866 字,大约阅读时间需要 12 分钟。

Android Handler 中的 IdleHandler 详解

一. 序

Handler 机制是 Android 开发的基础知识,常见于面试中。如今,在面试中很少直接要求详细讲解 Handler 的机制,而是通过具体场景来测试候选人的理解深度。IdleHandler 因为相对少人使用,因此了解它的功能和使用场景尤为重要。

本文将深入探讨 Android Framework 中的 Handler 机制,特别是 IdleHandler 的功能、使用方法以及在开发中的适用场景。


二. IdleHandler 详解

2.1 简单介绍 Handler 机制

Handler 是 Android 中常用的事件驱动模型,核心由三部分组成:

  • MessageQueue:基于消息的优先级队列,用于管理消息。
  • Looper:事件循环,负责不断从 MessageQueue 中取出消息进行处理。
  • Handler:接收并处理消息,定义在 MessageQueue 中。
  • 注意: 早期,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 在哪些场景下执行?队列空闲有两种状态:

  • MessageQueue 为空:无消息需处理。
  • 延迟消息:下一条消息的时间晚于当前时间,需要滞后处理。

  • 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框架中的使用场景

  • ActivityThread.Idler:用于Activity恢复。
  • GcIdler:内存不足时自动触发GARbage Collection。
  • Instrumentation.ActivityGoing:Activity启动前添加。
  • Instrumentation.Idler:用于键盘相关处理。
  • TextToSpeechService.SynthThread:TTS完成后发送广播。

  • 三. 常见面试问题解析

    Q:IdleHandler 有什么用途?

    • 用于在消息队列空闲时执行任务。
    • 适用于需要在App休眠时进行操作,但不适合处理实时性要求高的任务。

    Q:是否需要成对使用add/remove?

    • 不是必须。返回值决定了是否移除IdleHandler。

    Q:为什么不会进入死循环?

    • 原因:
      • pendingIdleHandlerCount 只执行一次。
      • nextPollTimeoutMillis 设为0,不会因休眠进入死循环。

    Q:能否将启动服务的任务放入IdleHandler?

    • 不建议,因为时机不可控。如果消息队列忙碌,IdleHandler执行机会会很晚。

    Q:IdleHandler 的执行线程是什么?

    -由当前MessageQueue所属的Looper线程执行,可以在子线程构造Looper后使用。


    四. 小结

    IdleHandler 是Handler机制中的一个灵活工具,适用于需要在消息队列空闲时执行任务的场景。但其执行时机基于MessageQueue的状态,不可控,应用时需谨慎。

    转载地址:http://ppxtz.baihongyu.com/

    你可能感兴趣的文章
    统计学之变异系数与是非标志
    查看>>
    关于继承的一些基本知识
    查看>>
    抖音发布黄金时间段,抖音上热门最佳时间
    查看>>
    我的图床~
    查看>>
    Thymeleaf sec:authorize 标签不生效
    查看>>
    Iterable与Iterator
    查看>>
    Python机器学习(六十五)Matplotlib 入门
    查看>>
    关于WebView当前地址问题的疑惑
    查看>>
    Python机器学习(九十二)Pandas 统计
    查看>>
    项目实战从0到1之hive(24)企业级数据仓库构建(六):数仓理论及数仓搭建
    查看>>
    SecSolar:为代码“捉虫”,让你能更专心写代码
    查看>>
    Trying to construct an instance of an invalid type
    查看>>
    1965 - 2019 年最流行的编程语言变化
    查看>>
    链上钱包的博彩雷区
    查看>>
    GRUB2
    查看>>
    解决RHEL6 vncserver 启动 could not open default font 'fixed'错误.
    查看>>
    微信JS-SDK DEMO页面和示例代码
    查看>>
    Chrome查找发请求的js之黑箱调试
    查看>>
    CMCC登录参数分析
    查看>>
    GridView的另外一种分页方式,可提高加载速度
    查看>>