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

Android 計數器崩潰:子線程直接更新 UI 導致應用退出的根因與 Handler 修復方案

     編輯:程式設計綜合問答

崩潰代碼分析

b1.setOnClickListener(new OnClickListener() {
    public void onClick(View v) {
        class T1 extends Thread {
            int i = 0;
            public void run() {
                while (true) {
                    for (int j = 0; j < 60; j++) {
                        doit();
                    }
                    i = 0;
                }
            }
            public void doit() {
                try { sleep(1000); } catch (Exception e) {}
                tt3.setText("" + i);  // ❌ 致命錯誤:子線程更新 UI
                i++;
            }
        }
        new T1().start();
    }
});

根因:Android 單線程模型

  • Android UI 操作必須在主線程(UI 線程)執行
  • 子線程直接調用 View.setText() 會拋出 CalledFromWrongThreadException
  • 異常未捕獲導致應用崩潰退出

修復方案:Handler 機制

方案一:Handler + Message(推薦)

// 在 Activity 中定義 Handler
private Handler mHandler = new Handler(Looper.getMainLooper()) {
    @Override
    public void handleMessage(Message msg) {
        if (msg.what == 1) {
            tt3.setText(String.valueOf(msg.arg1));
        }
    }
};

// 子線程中發送消息
public void doit() {
    try { Thread.sleep(1000); } catch (Exception e) {}
    Message msg = mHandler.obtainMessage(1, i, 0);
    mHandler.sendMessage(msg);
    i++;
}

方案二:runOnUiThread

runOnUiThread(new Runnable() {
    @Override
    public void run() {
        tt3.setText(String.valueOf(i));
    }
});

方案三:View.post(Runnable)

tt3.post(new Runnable() {
    @Override
    public void run() {
        tt3.setText(String.valueOf(i));
    }
});

完整修正代碼

b1.setOnClickListener(v -> {
    new Thread(() -> {
        int i = 0;
        while (true) {
            for (int j = 0; j < 60; j++) {
                try { Thread.sleep(1000); } catch (InterruptedException e) { return; }
                final int current = i;
                runOnUiThread(() -> tt3.setText(String.valueOf(current)));
                i++;
            }
            i = 0;
        }
    }).start();
});

最佳實踐建議

  • 使用 Handler 而非 runOnUiThread 避免內存洩漏(靜態內部類 + WeakReference)
  • 考慮 CountDownTimer 替代手動睡眠循環
  • Kotlin 協程:withContext(Dispatchers.Main) { tt3.text = i.toString() }
  • 及時處理 InterruptedException 支持線程取消

核心原則

Android 視圖操作只能在主線程執行,跨線程更新 UI 必須通過消息隊列(Handler/Looper)分發到主線程。

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