浅析Hanlder消息队列处理各种消息的流程

今天咱们要把Android的Handler消息队列变成一个有趣的故事,让你像看漫画一样理解它的原理。

想象一下,你是一个超级英雄团队(Looper)指挥官(Handler) 。你的团队有一个至关重要的部门:任务调度中心(MessageQueue) 。这个中心的核心设备是一个超级智能的任务待办箱(MessageQueue的底层实现)

这个待办箱不简单,它不是一个普通的队列(先进先出),而是一个按"执行时间"自动排序的优先级队列 。每个任务(Message)上都贴着一个"几点几分开始做"的标签(when属性)。


故事人物介绍(代码对应)

  1. 指挥官(Handler) : 你,负责发送各种任务(Message)。

    • 对应代码:Handler handler = new Handler(Looper.getMainLooper());
  2. 任务调度中心(MessageQueue) : 一个存放所有任务的箱子。

    • 对应代码:Looper.myLooper().mQueue
  3. 超级英雄团队(Looper) : 一个永不停歇的团队,核心成员loop()方法会不停地从中心里取任务、执行任务。

    • 对应代码:Looper.loop()
  4. 普通任务(同步Message) : 标签上只有"执行时间"。

  5. VIP加急通道(同步屏障,SyncBarrier) : 一个特殊的令牌,一旦被放入待办箱,普通任务就得全部靠边站,只允许执行一种任务...

  6. 超级VIP加急任务(异步Message) : 标签上除了"执行时间",还盖了一个"加急"的章。只有在"VIP加急通道"开启时,它们才会被优先处理。


剧情开始:四连发任务指令

现在,你作为指挥官,在极短的时间内连续下达了四个指令(对应你的问题):

第1步:下达一个延迟任务
handler.postDelayed(msg1, 10000); // 10秒后执行msg1

  • 故事:你对任务中心说:"嘿,10秒钟后再处理这个msg1任务。"
  • 原理 :待办箱计算msg1.when = 当前时间(例如10:00:00) + 10000毫秒 = 10:00:10,然后把msg1放进箱子。箱子内部会自动根据when的时间进行排序。此时箱子里只有它一个,排在第一位。

第2步:下达一个即时任务
handler.post(msg2); // 立刻执行msg2

  • 故事:你马上又下达了一个新任务msg2:"这个立刻就要!"
  • 原理 :待办箱计算msg2.when = 当前时间(10:00:00) + 0毫秒 = 10:00:00。比较一下时间,10:00:00 比 10:00:10 要早!所以箱子会重新排序 ,把msg2插到msg1的前面。现在箱子里的顺序是:[msg2] -> [msg1]

第3步:开启VIP加急通道,并下达一个超级VIP延迟任务

java 复制代码
// 插入同步屏障(token可以理解为这个屏障的令牌)
int token = handler.getLooper().getQueue().postSyncBarrier();
// 发送一个异步消息,延迟20秒
handler.postDelayed(msg3, 20000);
Message msg3 = ...;
msg3.setAsynchronous(true); // 给msg3盖上"加急"章
  • 故事:你觉得可能有超级紧急的事会发生,于是你启动了"VIP加急通道"(同步屏障)。然后你又下达了一个任务msg3,但这个任务比较特殊:第一,它被标记为"加急"(异步);第二,它要20秒后才执行。

  • 原理

    • 同步屏障 :这其实是一个特殊的、没有when时间的"令牌"(Message)。它被放入待办箱后,不会被执行,它的作用就是"挡路"。它会插在当前所有任务中合适的位置。假设它被插入到了最前面。此时箱子里的"逻辑状态"是:[屏障] -> [msg2] -> [msg1]
    • 异步消息msg3 :待办箱计算msg3.when = 10:00:00 + 20000 = 10:00:20。因为它有"加急"章,所以它和屏障是一伙的。现在箱子里的完整顺序是:[屏障] -> [msg2] -> [msg1] -> [msg3]

第4步:再下达一个即时任务
handler.post(msg4); // 立刻执行msg4

  • 故事:你忘了还有个普通任务msg4要立刻处理。
  • 原理 :待办箱计算msg4.when = 10:00:00。它是个普通任务。此时箱子里的顺序是:[屏障] -> [msg4, when=10:00:00] -> [msg2, when=10:00:00] -> [msg1, when=10:00:10] -> [msg3, when=10:00:20]。注意,msg4msg2when时间相同,它们会按插入的先后顺序排列。

核心高潮:超级英雄团队(Looper)如何处理?

团队的核心成员loop()方法,他的工作就一句话: "死循环地从待办箱里取下一个要执行的任务,如果还没到点,就睡一会儿;如果取到的是普通任务,就执行它。"

下面是整个处理过程的时序图,清晰地展示了交互逻辑:

结合代码看关键点:

Looper.loop() 的核心代码段:

java 复制代码
public static void loop() {
    ...
    for (;;) {
        // 1. 取下一个消息,可能会阻塞
        Message msg = queue.next();
        if (msg == null) {
            return;
        }
        // 2. 分发消息给Handler
        msg.target.dispatchMessage(msg);
        ...
    }
}

MessageQueue.next() 的核心逻辑(简化故事版):

java 复制代码
Message next() {
    for (;;) {
        ...
        // 1. 如果队列头部队首是"同步屏障"
        if (msg != null && msg.target == null) { // target为null就是屏障
            // 开启VIP模式:跳过所有普通消息,只找第一个异步消息
            do {
                prevMsg = msg;
                msg = msg.next;
            } while (msg != null && !msg.isAsynchronous()); // 找到盖了"加急"章的
        }

        // 2. 找到了一个消息(可能是普通的,也可能是异步的)
        if (msg != null) {
            if (now < msg.when) {
                // 还没到点,计算要睡多久
                nextPollTimeoutMillis = (int) Math.min(msg.when - now, Integer.MAX_VALUE);
            } else {
                // 到点了!把这个消息从链子上摘下来,返回给Looper
                return msg;
            }
        } else {
            // 没找到消息,一直睡直到被新消息唤醒
            nextPollTimeoutMillis = -1;
        }
        ...
        // 3. 在这里进入休眠(nativePollOnce)
        nativePollOnce(ptr, nextPollTimeoutMillis);
    }
}

大结局

所以,最终四个消息的执行顺序是:

  1. msg2: 首先被处理,因为它是即时消息,且当时没有屏障。
  2. msg3 : 其次被处理。虽然它延迟20秒,但在屏障存在期间,Looper醒来后跳过了所有普通消息(msg4, msg1),发现最早的异步消息msg3到期后,就执行了它。 这发生在第20秒左右。
  3. msg4msg1只有当某个地方调用removeSyncBarrier(token)移除了同步屏障后 ,它们俩才有机会被执行。屏障一撤,Looper下次醒来就会按时间顺序处理积压的普通消息。所以先执行when更早的msg4(10:00:00),再执行msg1(10:00:10)。

总结一下精髓:

  • 排序依据MessageQueue永远按when的大小排列消息。
  • 同步屏障 :像一道开关,开启时(屏障在队列中),Looper会忽略所有同步消息,只处理异步消息。
  • 延迟 :不是指延迟X秒才放入队列,而是延迟X秒才有资格被取出执行。队列早就排好序了。
  • 唤醒机制 :每当新消息入队或屏障变化,都会尝试唤醒Looper,检查是否有更早的消息可以执行了。

这下是不是彻底明白了?Handler就像一个严格而又灵活的交通指挥官,而MessageQueue就是那条智能的高速公路,同步屏障就是应急车道,确保重要的任务(比如UI绘制)永远畅通无阻!

相关推荐
wj0718421542 小时前
Android 内存优化 第2篇
android
用户2018792831672 小时前
浅析Hanlder处理延时消息的流程
android
用户092 小时前
Android面试基础篇(一):基础架构与核心组件深度剖析
android·面试·kotlin
wow_DG4 小时前
【MySQL✨】MySQL 入门之旅 · 第十篇:数据库备份与恢复
android·数据库·mysql
00后程序员张4 小时前
iOS 26 系统流畅度深度剖析,Liquid Glass 视效与界面滑动的实际测评
android·macos·ios·小程序·uni-app·cocoa·iphone
草字5 小时前
Android studio 查看apk的包名,查看包名
android·ide·android studio
、BeYourself5 小时前
Android Studio 详细安装与配置指南
android
夜晚中的人海5 小时前
C++11(2)
android·数据库·c++
Kapaseker7 小时前
每个Kotlin开发者应该掌握的最佳实践,最后一趴
android·kotlin