时间线:
-
用户启动计时(25分钟)
-
用户切换到其他Fragment(如学习记录)
-
PomodoroFragment.onDestroyView()被调用 → 界面组件被销毁
-
但计时器仍在后台运行(CountDownTimer是独立线程)
-
25分钟后计时器完成,调用onFinish()
-
onFinish()中操作已销毁的btnStart → 空指针异常 → 应用崩溃
java
// 你的原始代码问题:
@Override
public void onFinish() {
isRunning = false;
btnStart.setText(R.string.start_study); // ❌ 危险操作
// ... 其他UI操作
}
java
// 你的原始代码:
private void finishStudy() {
if (countDownTimer != null) {
countDownTimer.cancel(); // ✅ 停止计时器
}
// ❌ 但没有立即更新isRunning状态
// ❌ 没有清空countDownTimer引用
resetTimer(); // 延迟的状态更新
}
// 用户点击完成按钮时:
finishStudy()被调用
↓
countDownTimer.cancel()被调用
↓
但此时:已经有一个onTick消息在Handler队列中等待执行!
↓
1秒后:队列中的onTick消息仍然执行 → 时间继续更新
↓
界面显示时间还在走
java
private void finishStudy() {
if (countDownTimer != null) {
countDownTimer.cancel(); // ❌ 只能阻止新消息,不能取消已进入队列的消息
}
// 但队列中可能已经有等待执行的onTick消息
}
java
private void finishStudy() {
// 立即停止计时器并更新状态
isRunning = false;
if (countDownTimer != null) {
countDownTimer.cancel();
countDownTimer = null; // 释放计时器引用
}
// ⭐⭐⭐ 关键修复:立即重置时间,防止Handler队列中的消息继续更新界面
timeLeftInMillis = 25 * 60 * 1000;
updateTimer(); // 立即更新界面显示
// 立即更新按钮状态
if (btnStart != null) {
btnStart.setText(R.string.start_study);
}
if (etTaskName != null) {
etTaskName.setEnabled(true);
}
if (startTimeMillis > 0 && timeLeftInMillis < 25 * 60 * 1000) {
saveStudyRecord();
}
resetTimer();
}
用户切换到其他Fragment → PomodoroFragment.onDestroyView()被调用
↓
但计时器仍在后台运行(因为onDestroyView()中没有停止计时器)
↓
用户在其他Fragment中点击完成按钮
↓
但此时PomodoroFragment的界面已销毁,btnReset的点击事件无法触发
↓
计时器继续运行,无法停止