Android IdleHandler源码分析

news/2024/7/19 1:59:57 标签: Android, IdleHandler, 源码分析

文章目录

Android_IdleHandler_1">Android IdleHandler源码分析

概述

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

前提

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

基本用法

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操作。

http://www.niftyadmin.cn/n/5548433.html

相关文章

大模型/NLP/算法面试题总结3——BERT和T5的区别?

1、BERT和T5的区别&#xff1f; BERT和T5是两种著名的自然语言处理&#xff08;NLP&#xff09;模型&#xff0c;它们在架构、训练方法和应用场景上有一些显著的区别。以下是对这两种模型的详细比较&#xff1a; 架构 BERT&#xff08;Bidirectional Encoder Representation…

井字游戏00

题目链接 井字游戏 题目描述 注意点 1 < board.length board[i].length < 100输入一定遵循井字棋规则 解答思路 如果某一方想要获胜&#xff0c;则其需要占满某一行或某一列或对角线&#xff0c;所以只需要根据第一行和第一列判断是否填充完某一行或某一列或对角线…

白骑士的C++教学基础篇 1.4 函数

系列目录 上一篇&#xff1a;白骑士的C教学基础篇 1.3 控制流 函数是编程中的基本构建块之一&#xff0c;它允许我们将代码组织成逻辑单元&#xff0c;提高代码的可读性和可维护性。C中的函数提供了丰富的功能&#xff0c;包括函数定义与调用、函数参数与返回值、函数重载和内…

获取商铺信息,以及商铺信息的增删改查

本文章主要讲述如何对商铺信息进行基本的增删改查操作&#xff0c;及数据库对比。 1、获取首页仪表盘统计数据接口 待收费金额&#xff1a; SELECT count(1) as count,IFNULL(sum(total),0)as sum FROM payment_bill WHERE enabled_mark 1 AND pay_state0 欠费数据&#xf…

ArkUI开发学习随机——B站视频简介页面,美团购买界面

案例一&#xff1a;B站视频简介页面 代码&#xff1a; build() {Column(){Column(){Stack(){Image($r("app.media.genimpact")).width(200).height(125).borderRadius({topLeft:5,topRight:5})Row(){Image($r("app.media.bz_play")).height(24).fillColor…

C#中,不同命名空间下面完全相同的类对象进行赋值

背景前提&#xff1a; 1、在命名空间ModelA、ModelB下&#xff0c;都有完全相同的类定义ClassX、ClassY、ClassZ &#xff1b; 2、ClassBase是父类&#xff0c;它的子类有&#xff1a;ClassX、ClassY、ClassZ 3、在ModelB下不能访问ModelA&#xff1b; 4、有大量文件&…

黑客出售 2024 年脸书个人资料数据

最近&#xff0c;一个地下论坛上的威胁行为者发布了涉嫌数据泄露的消息。 该事件涉及脸书用户的大型数据库被泄露。 泄露的数据包括敏感的用户信息&#xff0c;例如全名、个人资料、电子邮件、电话号码、出生日期和位置。 需要注意的是&#xff0c;这些信息来自网络犯罪分子…

数一140+上岸|七月强化一定要避开这3个雷区!

当然可以&#xff0c;强化阶段的主要任务就是做题&#xff01; 但是不用一刀切&#xff0c;强化阶段听课和做题可以二八原则&#xff0c;就是听课占20%&#xff0c;做题占80%。 因为自己去自学讲义的话&#xff0c;比如张宇18讲&#xff0c;会漏掉一些重点&#xff0c;有的技…