在 Android 開發中,新手常犯的錯誤是在 Activity 中直接啟動無限循環的執行緒或 AsyncTask 進行網路輪詢。當使用者離開頁面(onDestroy)時,這些後台任務若未正確取消,會繼續執行,導致:
// 問題代碼片段
new Thread() {
public void run() {
while (true) { // 無限循環,無退出機制
Thread.sleep(900);
new AnotherTask().execute("JSON"); // 額外創建 AsyncTask
}
}
}.start();
此處 while(true) 缺乏中斷條件,AsyncTask 亦未持有引用以便取消。
public class WaterActivity extends Activity {
private volatile boolean isRunning = false; // volatile 保證可見性
private Thread pollThread;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// ... 初始化視圖 ...
isRunning = true;
pollThread = new Thread(new PollRunnable());
pollThread.start();
}
class PollRunnable implements Runnable {
@Override
public void run() {
while (isRunning) { // 檢查標誌位
try {
Thread.sleep(900);
if (!isRunning) break; // 睡醒後再次檢查
// 在主執行緒更新 UI 或發送 Message
runOnUiThread(() -> new AnotherTask().execute("JSON"));
} catch (InterruptedException e) {
Thread.currentThread().interrupt(); // 重置中斷狀態
break; // 被 interrupt 時退出
}
}
}
}
@Override
protected void onDestroy() {
super.onDestroy();
isRunning = false; // 1. 設置標誌位
if (pollThread != null) {
pollThread.interrupt(); // 2. 中斷睡眠/阻塞
}
}
}
注意: AsyncTask 已在 Android 11 (API 30) 棄用,建議遷移至 ExecutorService + Future 或 Kotlin Coroutines/RxJava。若維護舊專案,必須實作:
private AnotherTask currentTask;
private class AnotherTask extends AsyncTask {
@Override
protected String doInBackground(String... params) {
// 定期檢查 isCancelled()
while (!isCancelled()) {
// 執行耗時操作...
if (isCancelled()) break;
}
return null;
}
@Override
protected void onPostExecute(String result) {
if (!isCancelled() && !isFinishing()) { // 雙重保險
addEntry(mChart1);
addEntry(mChart2);
}
}
}
@Override
protected void onDestroy() {
super.onDestroy();
if (currentTask != null) {
currentTask.cancel(true); // true 表示 mayInterruptIfRunning
}
}
onStart/onResume 啟動,onStop/onDestroy 停止。static 內部類 + WeakReference<Activity> 或 ViewBinding。lifecycleScope.launch { ... }) 或 Flow,自動處理生命週期取消,程式碼更簡潔安全。