Thread中直接調用TextView.setText() → CalledFromWrongThreadException:Android UI工具包非線程安全,**只有UI線程能訪問View**。
Handler handler = new Handler(Looper.getMainLooper()) {
@Override public void handleMessage(Message msg) {
textView.setText("更新內容");
}
};
// 子線程發送消息
new Thread(() -> {
handler.sendEmptyMessage(0);
}).start();
runOnUiThread(() -> textView.setText("更新內容"));
textView.post(() -> textView.setText("更新內容"));
public class MainActivity extends Activity {
TextView sendView, receiveView;
Handler handler = new Handler(Looper.getMainLooper());
boolean flag = false;
@Override
protected void onCreate(Bundle savedInstanceState) {
// ... findViewById ...
Button btnStart = findViewById(R.id.send);
btnStart.setOnClickListener(v -> {
flag = true;
new Thread(this::backgroundTask).start();
});
}
void backgroundTask() {
for (int i = 1; i <= 100 && flag; i++) {
final int value = i;
handler.post(() -> { // 切換到主線程
sendView.setText(String.valueOf(value));
receiveView.setText(String.valueOf(value));
});
try { Thread.sleep(1000); } catch (InterruptedException ignored) {}
}
}
}
Thread.sleep在子線程正常,主線程會ANR。Handler持有Looper引用,Looper.getMainLooper()綁定主線程消息隊列。static class MyHandler extends Handler + WeakReference,或removeCallbacksAndMessages(null)在onDestroy。