在 Android 開發中,使用 Timer 和 TimerTask 實現倒計時功能時,若分鐘與秒輸入框任一為空,程式即會崩潰。這是因為 Integer.parseInt() 在解析空字串時會拋出 NumberFormatException,導致應用程式異常終止。
原始碼在 onClick() 中直接對 EditText 取值並轉換:
i = Integer.parseInt(etSecond.getText().toString());
i2 = Integer.parseInt(etMinute.getText().toString());
當使用者未輸入數值時,getText().toString() 回傳空字串 "",導致解析失敗。
在解析前檢查輸入是否為空,若為空則視為 0:
String minStr = etMinute.getText().toString().trim();
String secStr = etSecond.getText().toString().trim();
i2 = TextUtils.isEmpty(minStr) ? 0 : Integer.parseInt(minStr);
i = TextUtils.isEmpty(secStr) ? 0 : Integer.parseInt(secStr);
TimerTask 執行於背景執行緒,更新 UI 需透過 Handler 切換至主執行緒,易造成記憶體洩漏與生命週期管理困難。建議改用 Handler.postDelayed() 實現倒計時:
private Handler handler = new Handler(Looper.getMainLooper());
private Runnable countdownRunnable = new Runnable() {
@Override
public void run() {
if (totalSeconds <= 0) {
time.setText("00:00");
return;
}
int min = totalSeconds / 60;
int sec = totalSeconds % 60;
time.setText(String.format(Locale.getDefault(), "%02d:%02d", min, sec));
totalSeconds--;
handler.postDelayed(this, 1000);
}
};
在 onDestroy() 中移除所有待執行任務,防止記憶體洩漏:
@Override
protected void onDestroy() {
super.onDestroy();
handler.removeCallbacks(countdownRunnable);
}
Android 內建 Chronometer 元件專為計時設計,支援格式化輸出、暫停/繼續、基準時間設定,無需自行處理執行緒與 UI 更新,程式碼更簡潔穩健:
<Chronometer
android:id="@+id/chronometer"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="40sp"
android:format="%s" />
Chronometer chronometer = findViewById(R.id.chronometer);
chronometer.setBase(SystemClock.elapsedRealtime() + totalSeconds * 1000);
chronometer.setOnChronometerTickListener((c) -> {
if (SystemClock.elapsedRealtime() >= c.getBase()) {
c.stop();
time.setText("00:00");
}
});
chronometer.start();
倒計時崩潰的根本原因是缺乏輸入驗證。建議採用 Handler + Runnable 或原生 Chronometer 替代 TimerTask,並完善生命週期管理,即可構建穩定、易維護的計時功能。