子線程向主線程發送消息,直接使用主線程的 Handler 實例即可,無需在子線程創建 Looper/Handler。 主線程(UI 線程)啟動時自動調用 Looper.prepareMainLooper() 並進入 Looper.loop(),因此天然擁有消息循環能力。
// 主線程持有子線程的 Handler
Handler workerHandler = new Handler(workerThread.getLooper());
// 發送任務
workerHandler.post(() -> {
// 這裡運行在子線程
doBackgroundWork();
});
// 主線程創建 Handler(關聯主線程 Looper)
Handler mainHandler = new Handler(Looper.getMainLooper()) {
@Override
public void handleMessage(@NonNull Message msg) {
// 這裡運行在主線程,安全更新 UI
updateUI(msg);
}
};
// 子線程中直接使用主線程 Handler
new Thread(() -> {
// 耗時操作...
Message msg = mainHandler.obtainMessage(WHAT_UPDATE, result);
msg.sendToTarget(); // 或 mainHandler.sendMessage(msg)
}).start();
Handler.sendMessage() 只是將 Message 推入目標 MessageQueue,不關心發送者是哪個線程。handleMessage() 執行於 Looper.loop() 所在線程,由目標 Handler 的 Looper 決定。同一線程可創建多個 Handler,分別處理不同業務消息(如 UI_HANDLER、NETWORK_HANDLER),通過 what 區分消息類型,實現邏輯解耦。所有 Handler 共享同一 MessageQueue,由同一 Looper 依次分發。
HandlerThread workerThread = new HandlerThread("Worker");
workerThread.start();
// 獲取綁定該線程 Looper 的 Handler
Handler workerHandler = new Handler(workerThread.getLooper());
// 使用完畢釋放
workerThread.quitSafely(); // API 18+
| 錯誤做法 | 後果 | 正確做法 |
|---|---|---|
| 子線程 new Handler() 無參構造 | 綁定當前線程 Looper,若未 prepare() 崩潰 | 傳入 Looper.getMainLooper() 或 workerThread.getLooper() |
| 主線程執行耗時操作 | ANR(Application Not Responding) | 耗時操作拋給子線程,結果回主線程 Handler |
| Activity 銷毀後 Handler 持有引用 | 內存洩漏、UI 更新崩潰 | 使用靜態內部類 + WeakReference,或 removeCallbacksAndMessages(null) |
Android 線程通信本質是「生產者將消息投遞到消費者的消息隊列」。主線程自帶 Looper,是天然的消費者;子線程若需接收消息,需自備 Looper(推薦 HandlerThread)。掌握「誰的 Looper,誰的線程執行 handleMessage」核心原理,即可靈活設計各類異步協作場景。