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

Android ProgressBar 配合 Handler 多執行緒更新 UI 完整解析

     編輯:程式設計綜合問答

程式碼走讀

public class MainActivity extends ActionBarActivity {
    private int[] data = new int[100];
    int hasData = 0, status = 0;
    ProgressBar bar, bar2;
    
    // Handler 定義:處理子執行緒送來的訊息
    Handler mHandler = new Handler() {
        @Override
        public void handleMessage(Message msg) {
            if (msg.what == 0x111) { // 訊息類型匹配
                bar.setProgress(status);   // 更新進度條 1
                bar2.setProgress(status);  // 更新進度條 2
            }
        }
    };

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        bar = findViewById(R.id.bar);
        bar2 = findViewById(R.id.bar2);
        
        // 啟動子執行緒模擬耗時工作
        new Thread() {
            public void run() {
                while (status < 100) {
                    status = doWork();           // 產生資料、睡眠 1 秒
                    mHandler.sendEmptyMessage(0x111); // 通知 UI 執行緒更新
                }
            }
        }.start();
    }

    public int doWork() {
        data[hasData++] = (int)(Math.random() * 100);
        try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); }
        return hasData; // 返回已產生資料筆數 (0~100)
    }
}

關鍵機制解析

元件角色說明
子執行緒 (`new Thread`)背景工作執行 `doWork()`,不可直接操作 UI (會拋 `CalledFromWrongThreadException`)。
`Handler`跨執行緒通訊建立在 **UI 執行緒** (主執行緒),其 `Looper` 綁定主執行緒訊息隊列。`sendEmptyMessage` 將訊息推入隊列,`handleMessage` 在 **UI 執行緒** 執行。
`Message.what = 0x111`訊息識別碼自訂整數,用於區分不同訊息類型。此處單一類型,固定 0x111。
`ProgressBar.setProgress`UI 更新必須在 UI 執行緒呼叫,`Handler` 保證此點。

流程圖

主執行緒 (UI)                     子執行緒 (Worker)
    │                                  │
    │  建立 Handler (綁定主 Looper)    │
    │─────────────────────────────────►│
    │                                  │  while(status<100)
    │                                  │      status = doWork()
    │                                  │      Thread.sleep(1000)
    │                                  │      sendEmptyMessage(0x111)
    │◄─────────────────────────────────│
    │  handleMessage(0x111)            │
    │      bar.setProgress(status)     │
    │      bar2.setProgress(status)    │
    │                                  │

現代替代方案

  • `runOnUiThread(Runnable)`**:`runOnUiThread(() -> bar.setProgress(status));` 簡潔,無需 Handler。
  • Kotlin 協程**:`lifecycleScope.launch { while(status<100) { status = doWork(); withContext(Dispatchers.Main) { bar.progress = status } delay(1000) } }`
  • RxJava / Flow / LiveData**:響應式資料流自動切換執行緒。

常見坑

  1. 子執行緒直接 `bar.setProgress()` → 崩潰。
  2. `Handler` 建立在子執行緒 → `handleMessage` 仍在子執行緒執行,更新 UI 失敗。必須在 `onCreate` (主執行緒) 建立。
  3. 未處理 `Activity` 銷毀後訊息仍送達 → 記憶體洩漏。解決:`static class MyHandler extends Handler { WeakReference ref; ... }` 或 `removeCallbacksAndMessages(null)` 在 `onDestroy`。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved