您好,登录后才能下订单哦!
# 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:消息处理器,承担发送和处理双重角色
发送端Handler -> MessageQueue.enqueueMessage()
↓
Looper.loop() -> MessageQueue.next()
↓
目标Handler.dispatchMessage()
handler.sendMessage(msg1);
handler.sendMessage(msg2);
// 执行顺序:msg1 → msg2
同步发送时,消息按调用顺序严格进入队列尾部,形成FIFO(先进先出)结构。这种顺序在单线程环境下绝对可靠。
Message msg = Message.obtain();
msg.setAsynchronous(true); // 标记为异步消息
handler.sendMessage(msg);
异步消息(通过setAsynchronous(true)
标记)在API 16+引入,主要用于系统级高优先级消息(如VSync事件),但在普通消息队列中仍按入队时间排序。
handler.sendMessageDelayed(msg1, 1000); // 1秒延迟
handler.sendMessage(msg2); // 立即发送
延迟消息通过when
字段记录目标执行时间:
1. 消息入队时根据SystemClock.uptimeMillis() + delay
计算when
2. MessageQueue按when
值升序排列
3. 即使后发送的msg2也会因更小的when
值排在msg1前
// 伪代码展示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唤醒
// 系统内部使用代码
mQueue.postSyncBarrier();
特殊场景下的顺序调整: 1. 同步屏障(token != 0的消息)会阻塞后续同步消息 2. 只有异步消息能越过屏障处理 3. 屏障移除后恢复同步消息处理 4. 典型应用场景:ViewRootImpl的绘制流程
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()
Handler handler = new Handler() {
@Override
public void handleMessage(Message msg) {
// 可能永远不会执行
}
};
// 发送Runnable会覆盖同名Message处理
handler.post(() -> {...});
handler.sendEmptyMessage(0);
// 同一线程创建多个Handler
Handler handler1 = new Handler();
Handler handler2 = new Handler();
handler1.sendMessage(msg1);
handler2.sendMessage(msg2);
虽然Handler不同,但共享同一个MessageQueue: - 消息仍然严格按时序排列 - 处理时根据Message.target字段路由到对应Handler
// 线程A
handlerB.sendMessage(msg);
// 线程B的Handler
Handler handlerB = new Handler(threadBLooper) {...}
跨线程发送存在潜在问题: 1. 发送操作线程安全(通过synchronized保证) 2. 但无法保证目标线程的处理速度 3. 可能产生”发送早却处理晚”的现象
handler.sendMessageAtFrontOfQueue(msg);
强制插入队列头部的注意事项: 1. 消息会跳过所有未执行的普通消息 2. 但不能越过同步屏障 3. 滥用可能导致消息饥饿
handler.removeMessages(WHAT_CODE);
消息移除的边界条件: 1. 只能移除尚未开始处理的消息 2. 正在dispatch的消息无法取消 3. 批量移除时按队列顺序扫描
adb shell dumpsys activity processes | grep -A10 "Message Queue"
通过系统工具检测: - 检查队列深度(pending消息数量) - 分析延迟消息的when值 - 识别阻塞的同步屏障
// 替代多次sendMessage
handler.removeMessages(WHAT_UPDATE);
handler.sendEmptyMessage(WHAT_UPDATE);
适用场景: - 频繁触发的UI更新 - 状态同步事件 - 进度报告消息
// 避免短间隔延迟消息链
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格式要求)
免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。