Android IdleHandler源码分析

Android IdleHandler源码分析

概述

IdleHandler是一个接口,它定义在MessageQueue类中,用于在主线程的消息队列空闲时执行一些轻量级的任务。IdleHandler接口有一个方法queueIdle(),其返回值决定了IdleHandler的后续行为。

前提

  • ThreadLocal:线程内的局部变量,存储Looper对象。
  • Looper:处理消息,存储MessageQueue对象。
  • MessageQueue:消息队列,内部维护 Message mMessages ArrayList<IdleHandler> mIdleHandlers
    • mMessages:通过 Handler 发送的消息。
    • mIdleHandlers:列表,存储 IdleHandler 任务。

基本用法

MessageQueue.IdleHandler mIdleHandler = new MessageQueue.IdleHandler() {
    @Override
    public boolean queueIdle() {
        // TODO
        return false;
    }
};

返回值:

  • false:只执行一次。
  • true:主线程空闲时会继续执行。

源码分析

添加和删除任务

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

public void removeIdleHandler(@NonNull IdleHandler handler) {
    synchronized (this) {
        mIdleHandlers.remove(handler);
    }
}

执行任务

最终会调用 MessageQueue#next() 方法。

Message next() { 

    int pendingIdleHandlerCount = -1;
    // nextPoll超时时间
    // 如果为-1,表示阻塞等待唤醒
    // 如果为0,则表示不阻塞
    // 如果为>0,则表示超时唤醒
    int nextPollTimeoutMillis = 0;
    for (;;) {
        if (nextPollTimeoutMillis != 0) {
            Binder.flushPendingCommands();
        }

        // 是否休眠阻塞
        nativePollOnce(ptr, nextPollTimeoutMillis);

        synchronized (this) {
            final long now = SystemClock.uptimeMillis();
            Message prevMsg = null;
            Message msg = mMessages;
            if (msg != null && msg.target == null) {
                do {
                    prevMsg = msg;
                    msg = msg.next;
                } while (msg != null && !msg.isAsynchronous());
            }
            if (msg != null) {
                // 表示MessageQueue有消息
                if (now < msg.when) {
                    // 就算休眠时间
                    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 {
                // 表示MessageQueue无消息,nextPollTimeoutMillis设置为-1,nativePollOnce无限等待,直到有消息
                nextPollTimeoutMillis = -1;
            }

            // 消息队列里的消息已经执行完了,处于空闲状态
            if (mQuitting) {
                dispose();
                return null;
            }

            // 获取IdleHandler任务数量
            if (pendingIdleHandlerCount < 0
                && (mMessages == null || now < mMessages.when)) {
                pendingIdleHandlerCount = mIdleHandlers.size();
            }
            // 如果为空,则不执行进入下一个循环
            if (pendingIdleHandlerCount <= 0) {
                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];
            mPendingIdleHandlers[i] = null; // 置空

            boolean keep = false;
            try {
                // 执行IdleHanlder任务,调用queueIdle()方法,并获取返回值
                keep = idler.queueIdle();
            } catch (Throwable t) {
                Log.wtf(TAG, "IdleHandler threw exception", t);
            }

            // 如果返回值为false,则从IdleHandlers列表中删除
            if (!keep) {
                synchronized (this) {
                    mIdleHandlers.remove(idler);
                }
            }
        }

        // 置空
        pendingIdleHandlerCount = 0;

        // 设置为0
        nextPollTimeoutMillis = 0;
    }
}

流程说明:

  • 如果本次循环获取的 Message 为空或是一个延迟消息,则表明当前队列为空闲状态。
  • 遍历mIdleHandlers列表,调用queueIdle()方法。
  • queueIdle()的返回值为false,表示从mIdleHandlers列表中删除;返回值为true,表示下次队列空闲时继续调用。

应用场景

  • 启动优化:非必要的代码可以放在 IdleHandler 中处理。
  • 加载优化:通过 IdleHandler 进行预加载。
  • 第三方框架:LeacCanary、Glide。
  • Android系统:GcIdler 空闲时进行GC操作。

相关推荐

  1. SDWebImage分析

    2024-07-10 11:44:03       28 阅读

最近更新

  1. docker php8.1+nginx base 镜像 dockerfile 配置

    2024-07-10 11:44:03       99 阅读
  2. Could not load dynamic library ‘cudart64_100.dll‘

    2024-07-10 11:44:03       107 阅读
  3. 在Django里面运行非项目文件

    2024-07-10 11:44:03       90 阅读
  4. Python语言-面向对象

    2024-07-10 11:44:03       98 阅读

热门阅读

  1. docker-1

    docker-1

    2024-07-10 11:44:03      28 阅读
  2. Git批量删除本地h和远程分支说明

    2024-07-10 11:44:03       28 阅读
  3. mvccaa

    2024-07-10 11:44:03       26 阅读
  4. Linux 常用指令详解

    2024-07-10 11:44:03       27 阅读
  5. 第2章 源码编译构建LAMP

    2024-07-10 11:44:03       18 阅读
  6. 数据库doris中的tablet底层解析

    2024-07-10 11:44:03       24 阅读
  7. 使用Python threading模块创建多线程程序

    2024-07-10 11:44:03       25 阅读
  8. 探索数据的奥秘:sklearn中的聚类分析技术

    2024-07-10 11:44:03       25 阅读
  9. FPGA之术语

    2024-07-10 11:44:03       26 阅读
  10. 【Axure视频教程】页面滚动距离函数

    2024-07-10 11:44:03       26 阅读