首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> Java 程式設計 >> Java 相關知識

Android 非同步訊息機制深度解析:Handler、Looper、Message 三大核心

     編輯:Java 相關知識

為什麼需要非同步訊息機制?

Android 單執行緒模型:UI 操作只能在主執行緒。耗時任務(網路、IO、計算)必須在子執行緒,完成後需將結果傳回主執行緒更新 UI。Handler-Looper-Message 正是官方提供的跨執行緒通訊標準機制。

三大角色職責

  • Message:資料載體,攜帶 what、obj、arg1/arg2、callback(Runnable)
  • MessageQueue:訊息佇列(單向鏈結串列),FIFO 儲存 Message
  • Looper:綁定執行緒,持有 MessageQueue,loop() 無限迴圈取出 Message 分派
  • Handler:發送/處理 Message 的介面,綁定特定 Looper(預設當前執行緒 Looper)

啟動流程源碼追蹤

1. Looper.prepare()

// ThreadLocal 確保每執行緒唯一 Looper
static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<>();

public static void prepare() {
    if (sThreadLocal.get() != null)
        throw new RuntimeException("Only one Looper per thread");
    sThreadLocal.set(new Looper(true)); // 建立 Looper 並綁定 MessageQueue
}

2. Looper.loop()


public static void loop() {
    Looper me = myLooper(); // 取得當前執行緒 Looper
    MessageQueue queue = me.mQueue;

    for (;;) { // 無限迴圈
        Message msg = queue.next(); // 阻塞等待訊息
        if (msg == null) return;    // queue 退出

        // 分派給目標 Handler
        msg.target.dispatchMessage(msg);

        // 回收 Message 物件(物件池模式)
        msg.recycle();
    }
}

3. Handler 建構子綁定 Looper


public Handler() {
    mLooper = Looper.myLooper(); // 取得當前執行緒 Looper
    if (mLooper == null)
        throw new RuntimeException("No Looper; prepare() not called");
    mQueue = mLooper.mQueue; // 共享 MessageQueue
}

4. Handler.sendMessage() 入列流程


public boolean sendMessage(Message msg) {
    return sendMessageDelayed(msg, 0);
}

private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
    msg.target = this; // 關鍵:標記目標 Handler
    return queue.enqueueMessage(msg, uptimeMillis);
}

5. Handler.dispatchMessage() 分派邏輯


public void dispatchMessage(Message msg) {
    if (msg.callback != null) {           // 1. post(Runnable) 回調
        handleCallback(msg);
    } else if (mCallback != null) {       // 2. 建構子傳入 Callback
        if (mCallback.handleMessage(msg)) return;
        handleMessage(msg);               // 3. 預設 handleMessage(子類別覆寫)
    } else {
        handleMessage(msg);
    }
}

post(Runnable) 原理揭秘


public final boolean post(Runnable r) {
    return sendMessageDelayed(getPostMessage(r), 0);
}

private static Message getPostMessage(Runnable r) {
    Message m = Message.obtain(); // 從物件池取得
    m.callback = r;               // 封裝 Runnable
    return m;
}

dispatchMessage 發現 msg.callback != null 直接執行 handleCallback → 執行 r.run()。並未建立新執行緒,仍在 Looper 所屬執行緒(通常是主執行緒)執行。

子執行緒建立 Handler 正確姿勢


new Thread() {
    Handler handler;
    @Override public void run() {
        Looper.prepare();               // 1. 建立 Looper
        handler = new Handler() {
            @Override public void handleMessage(Message msg) {
                // 處理訊息,執行緒為此子執行緒
            }
        };
        Looper.loop();                  // 2. 開啟迴圈
    }
}.start();

其他執行緒可透過此 handler 發送訊息,處理邏輯將在該子執行緒執行。

記憶體洩漏風險與最佳實務

風險原因解決方案
非靜態內部類 Handler 持有外部類引用Message 延遲執行導致 Activity 無法 GC靜態內部類 + WeakReference<Activity>
delayed 訊息未移除Activity 銷毀前未 removeCallbacksAndMessages(null)onDestroy() 統一清理
靜態 Handler 持有 Context同樣導致洩漏避免靜態持有 Context,或使用 Application Context

現代替代方案

  • Kotlin Coroutines:withContext(Dispatchers.Main) 取代 Handler
  • Flow / LiveData / RxJava:反應式串流自動處理執行緒切換
  • Jetpack Lifecycle:lifecycleScope.launch 自動取消

結語

Handler-Looper-Message 是 Android 核心基礎設施,理解其「單執行緒循環 + 訊息佇列 + 目標分派」架構,能深度掌握跨執行緒通訊本質。雖現代開發推薦協程與反應式框架,但閱讀源碼、除錯 ANR、分析第三方庫行為時,這套機制知識不可或缺。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved