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

Android ProgressBar 進度獲取為 0?揭秘線程競態與正確異步模式

     編輯:程式設計疑難解答

現象複現

啟動進度條動畫後立即在主線程讀取 progressBar.getProgress(),打斷點調試時能拿到遞增值,直接運行卻始終為 0。

// 啟動動畫線程
new Thread(() -> {
    while (progress <= 58) {
        progress += 2;
        progressBar.setProgress(progress); // UI 線程更新
        Thread.sleep(70);
    }
}).start();

// 主線程立即讀取
int current = progressBar.getProgress(); // 結果為 0

根本原因:線程競態

  • 調試模式:斷點暫停主線程,給了動畫線程充足 CPU 時間片,進度條已更新完畢,讀取到非 0 值。
  • 直接運行:主線程極快執行到 getProgress(),此時動畫線程尚未開始或未來得及第一次 setProgress,進度條仍為初始值 0。

本質是 「發起異步操作後同步讀取結果」 的經典錯誤模式。

正確解決方案

方案一:Handler 機制(輕量)

Handler handler = new Handler(Looper.getMainLooper());
handler.postDelayed(() -> {
    int current = progressBar.getProgress(); // 確保在 UI 線程、動畫啟動後讀取
    // 處理 current...
}, 100); // 延遲略大於動畫啟動時間

方案二:AsyncTask / Kotlin 協程(結構化並發)


// Kotlin 協程示例
lifecycleScope.launch {
    startProgress() // 掛起函數,內部用 delay 替代 Thread.sleep
    val current = progressBar.progress // 協程恢復時動畫已完成或處於特定狀態
}

方案三:回調接口(最通用)


interface ProgressListener {
    void onProgressUpdate(int progress);
    void onProgressFinish(int finalProgress);
}

// 動畫線程中
listener.onProgressUpdate(progress);
// 結束時
listener.onProgressFinish(progress);

核心原則

UI 組件狀態變更是異步的,永遠不要在發起異步操作的同步上下文中直接讀取其結果。通過回調、監聽器、協程、Flow/LiveData 等機制在「狀態確定後」獲取數據。

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