首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> 更多程式語言 >> 程式設計綜合問答

Android Handler postDelayed 非同步陷阱:正確實現循序執行邏輯

     編輯:程式設計綜合問答

問題重現

開發者常寫出如下程式碼,期望「延遲 3 秒設定旗標 → 再執行 if 區塊」:

Permissions_flag = false;
new Handler().postDelayed(new Runnable() {
    @Override public void run() {
        Permissions_flag = true;
        Log.e("handler", "start");
    }
}, 3000);

if (Permissions_flag) {  // 此處立即執行,flag 仍為 false
    // 權限處理邏輯
}

結果:if 區塊立即執行,完全不等待 3 秒延遲,因為 postDelayed 只是將 Runnable 排入主執行緒訊息佇列,當前執行緒繼續往下跑。

核心概念:非同步 vs 同步

  • postDelayed 是非同步操作:排程未來執行,當下不阻塞。
  • 主執行緒(UI 執行緒)以 Looper 循環處理訊息佇列。
  • 後續程式碼在同一個呼叫堆疊繼續執行,不會等待排程任務完成。

解決方案一:將後續邏輯移入 Runnable 內部(最簡單)

new Handler(Looper.getMainLooper()).postDelayed(() -> {
    Permissions_flag = true;
    Log.e("handler", "start");
    // 直接在這裡執行原本 if 區塊的邏輯
    handlePermissions();
}, 3000);

解決方案二:使用 Kotlin Coroutines(現代寫法)

lifecycleScope.launch {
    delay(3000)  // 非阻塞暫停 3 秒
    Permissions_flag = true
    handlePermissions()  // 這裡會在 3 秒後執行
}

需在 build.gradle 引入 androidx.lifecycle:lifecycle-runtime-ktx。

解決方案三:傳統 Handler + Message 機制

Handler handler = new Handler(Looper.getMainLooper()) {
    @Override
    public void handleMessage(Message msg) {
        if (msg.what == 1) {
            handlePermissions();
        }
    }
};

new Thread(() -> {
    try { Thread.sleep(3000); } catch (InterruptedException ignored) {}
    handler.sendEmptyMessage(1);
}).start();

解決方案四:CountDownLatch(僅限背景執行緒)

嚴禁在主執行緒使用,會導致 ANR。若在 Worker Thread 中需等待:

CountDownLatch latch = new CountDownLatch(1);
new Handler(Looper.getMainLooper()).postDelayed(() -> {
    Permissions_flag = true;
    latch.countDown();
}, 3000);

try { latch.await(); } catch (InterruptedException ignored) {}
handlePermissions();

最佳實務建議

  1. 優先使用 Kotlin Coroutines,程式碼線性、易讀、自動處理生命週期。
  2. Java 專案若無法用 Coroutines,採用方案一:邏輯內移至 Runnable。
  3. 避免使用全域旗標 Permissions_flag 協調非同步流程,極易產生競態條件。
  4. 所有 UI 更新必須在主執行緒,使用 Handler(Looper.getMainLooper()) 確保執行緒正確。

結語

postDelayed 不會阻塞當前執行緒,這是 Android 非同步程式設計的基礎特性。理解「排程 ≠ 等待」,將後續邏輯封裝在回呼或協程中,才能寫出正確的循序執行程式碼。

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