# 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進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。