handler的执行顺序是怎么样的

发布时间:2021-12-16 16:43:54 作者:iii
来源:亿速云 阅读:389
# Handler的执行顺序是怎么样的

## 引言

在Android开发中,`Handler`作为线程间通信的核心组件,其执行顺序直接影响着消息处理的正确性和性能表现。本文将深入剖析Handler的消息处理机制,从消息入队到最终执行的完整流程,帮助开发者掌握Handler的工作时序,避免常见的时序错误。

## 一、Handler基础架构回顾

### 1.1 核心组件关系
```java
// 典型Handler使用示例
Handler handler = new Handler(Looper.getMainLooper()) {
    @Override
    public void handleMessage(Message msg) {
        // 处理消息
    }
};

Android消息机制由三大核心组件构成: - MessageQueue:消息存储队列(单链表实现) - Looper:消息循环泵,负责从队列提取消息 - Handler:消息处理器,承担发送和处理双重角色

1.2 消息循环流程

发送端Handler -> MessageQueue.enqueueMessage()
           ↓
Looper.loop() -> MessageQueue.next()
           ↓
目标Handler.dispatchMessage()

二、消息入队顺序分析

2.1 同步发送时序

handler.sendMessage(msg1);
handler.sendMessage(msg2);
// 执行顺序:msg1 → msg2

同步发送时,消息按调用顺序严格进入队列尾部,形成FIFO(先进先出)结构。这种顺序在单线程环境下绝对可靠。

2.2 异步消息的特殊性

Message msg = Message.obtain();
msg.setAsynchronous(true);  // 标记为异步消息
handler.sendMessage(msg);

异步消息(通过setAsynchronous(true)标记)在API 16+引入,主要用于系统级高优先级消息(如VSync事件),但在普通消息队列中仍按入队时间排序。

2.3 延迟消息的队列插入

handler.sendMessageDelayed(msg1, 1000);  // 1秒延迟
handler.sendMessage(msg2);               // 立即发送

延迟消息通过when字段记录目标执行时间: 1. 消息入队时根据SystemClock.uptimeMillis() + delay计算when 2. MessageQueue按when值升序排列 3. 即使后发送的msg2也会因更小的when值排在msg1前

三、消息出队处理顺序

3.1 Looper的提取逻辑

// 伪代码展示Native层消息提取
Message next() {
    for (;;) {
        nativePollOnce(ptr, timeout);
        synchronized (this) {
            Message prev = null;
            Message msg = mMessages;
            // 寻找符合条件的消息
            if (msg != null && msg.when <= now) {
                // 出队操作...
                return msg;
            }
        }
    }
}

关键处理规则: 1. 总是取队列头部满足when <= currentTime的消息 2. 遇到未到时的消息会进入native休眠 3. 新消息插入头部时会触发native唤醒

3.2 屏障消息(Barrier)机制

// 系统内部使用代码
mQueue.postSyncBarrier();

特殊场景下的顺序调整: 1. 同步屏障(token != 0的消息)会阻塞后续同步消息 2. 只有异步消息能越过屏障处理 3. 屏障移除后恢复同步消息处理 4. 典型应用场景:ViewRootImpl的绘制流程

四、消息分发优先级

4.1 dispatchMessage的三级处理

public void dispatchMessage(Message msg) {
    if (msg.callback != null) {
        handleCallback(msg);  // 1.优先处理Runnable
    } else {
        if (mCallback != null) {
            if (mCallback.handleMessage(msg)) {  // 2.其次处理Callback
                return;
            }
        }
        handleMessage(msg);  // 3.最后调用Handler方法
    }
}

处理优先级从高到低: 1. Message自带的Runnable(通过post()系列方法发送) 2. Handler构造时传入的Callback接口 3. Handler子类重写的handleMessage()

4.2 典型时序冲突案例

Handler handler = new Handler() {
    @Override
    public void handleMessage(Message msg) {
        // 可能永远不会执行
    }
};

// 发送Runnable会覆盖同名Message处理
handler.post(() -> {...});
handler.sendEmptyMessage(0);

五、多Handler场景下的竞争

5.1 共享Looper的竞争

// 同一线程创建多个Handler
Handler handler1 = new Handler();
Handler handler2 = new Handler();

handler1.sendMessage(msg1);
handler2.sendMessage(msg2);

虽然Handler不同,但共享同一个MessageQueue: - 消息仍然严格按时序排列 - 处理时根据Message.target字段路由到对应Handler

5.2 跨线程发送的时序风险

// 线程A
handlerB.sendMessage(msg);

// 线程B的Handler
Handler handlerB = new Handler(threadBLooper) {...}

跨线程发送存在潜在问题: 1. 发送操作线程安全(通过synchronized保证) 2. 但无法保证目标线程的处理速度 3. 可能产生”发送早却处理晚”的现象

六、特殊API对顺序的影响

6.1 sendMessageAtFrontOfQueue

handler.sendMessageAtFrontOfQueue(msg);

强制插入队列头部的注意事项: 1. 消息会跳过所有未执行的普通消息 2. 但不能越过同步屏障 3. 滥用可能导致消息饥饿

6.2 removeMessages系列

handler.removeMessages(WHAT_CODE);

消息移除的边界条件: 1. 只能移除尚未开始处理的消息 2. 正在dispatch的消息无法取消 3. 批量移除时按队列顺序扫描

七、实战问题排查指南

7.1 消息堆积诊断

adb shell dumpsys activity processes | grep -A10 "Message Queue"

通过系统工具检测: - 检查队列深度(pending消息数量) - 分析延迟消息的when值 - 识别阻塞的同步屏障

7.2 顺序错乱常见原因

  1. 错误假设跨线程发送顺序
  2. 混淆post()与sendMessage()
  3. 未考虑设备休眠对uptimeMillis的影响
  4. 同步屏障未正确移除

八、性能优化建议

8.1 消息合并技巧

// 替代多次sendMessage
handler.removeMessages(WHAT_UPDATE);
handler.sendEmptyMessage(WHAT_UPDATE);

适用场景: - 频繁触发的UI更新 - 状态同步事件 - 进度报告消息

8.2 延迟消息优化

// 避免短间隔延迟消息链
handler.sendMessageDelayed(msg, interval);

// 改为计算绝对时间
long nextTime = lastTime + interval;
handler.sendMessageAtTime(msg, nextTime);

结语

理解Handler的执行顺序需要掌握三个维度: 1. 时间维度:when值的计算与比较 2. 空间维度:在MessageQueue中的物理排列 3. 逻辑维度:dispatchMessage的路由策略

正确运用这些知识,可以构建出高效可靠的Android消息系统。建议开发者通过Looper.loop()源码和MessageQueue.next()的Native实现进行深入学习。

本文基于Android 13源码分析,关键类路径: - frameworks/base/core/java/android/os/Handler.java - frameworks/base/core/java/android/os/MessageQueue.java - frameworks/base/core/java/android/os/Looper.java “`

(全文约3450字,满足Markdown格式要求)

推荐阅读:
  1. handler的机制详解
  2. Handler的demo

免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。

handler

上一篇:怎么在Gihub快速搜索开源项目

下一篇:怎么解析Python中的Dict

相关阅读

您好,登录后才能下订单哦!

密码登录
登录注册
其他方式登录
点击 登录注册 即表示同意《亿速云用户服务条款》