# 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进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。