Android服务定时器结束后如何重新启用按钮?
解决定时器结束后按钮无法启用的问题
嘿,我看了你的代码,发现几个导致按钮在计时结束后没恢复启用的关键问题,咱们一步步来修复:
问题根源
- SharedPreferences提交遗漏:在Service的
TimeDifference()方法里,当long_hours == 0时,你设置了mEditor.putBoolean("finish", true)但没调用commit(),导致这个状态没真正保存到本地。 - Activity未收到结束通知:你的BroadcastReceiver只接收时间更新,完全不知道计时已经结束了,自然不会去启用按钮——毕竟MainActivity只有在
onResume时才会读取SharedPreferences,可计时结束时Activity很可能一直在前台,不会触发onResume。
修改方案
第一步:完善TimerService的计时结束逻辑
在Service里,当计时结束时,不仅要停止定时器、保存状态,还要给MainActivity发一个明确的结束信号,同时确保SharedPreferences的修改提交:
public class Timer_Service extends Service { public static String str_receiver = "com.countdowntimerservice.receiver"; // 新增一个结束状态的extra key public static final String EXTRA_IS_FINISHED = "is_finished"; // ... 其他原有代码 public String TimeDifference() { try { date_current = simpleDateFormat.parse(strDate); } catch (Exception e) { } try { date_diff = simpleDateFormat.parse(mpref.getString("data", "")); } catch (Exception e) { } try { long diff = date_current.getTime() - date_diff.getTime(); int int_hours = Integer.valueOf(mpref.getString("hours", "")); long int_timer = TimeUnit.MINUTES.toMillis(int_hours); long long_hours = int_timer - diff; long diffSeconds2 = long_hours / 1000 % 60; long diffMinutes2 = long_hours / (60 * 1000) % 60; if (long_hours >= 0) { String timeLeftFormatted = String.format(Locale.getDefault(), "%02d:%02d", diffMinutes2, diffSeconds2); Log.e("TIME", timeLeftFormatted); if (long_hours == 0){ mEditor.putBoolean("finish", true); mEditor.commit(); // 这里必须调用commit! mTimer.cancel(); // 发送结束信号 updateTime(timeLeftFormatted, true); } else { updateTime(timeLeftFormatted, false); } } else { mEditor.putBoolean("finish", true).commit(); mTimer.cancel(); updateTime("00:00", true); } }catch (Exception e){ mTimer.cancel(); mTimer.purge(); mEditor.putBoolean("finish", true).commit(); updateTime("00:00", true); } return ""; } // 修改updateTime方法,增加是否结束的参数 private void updateTime(String str_time, boolean isFinished){ intent.putExtra("time",str_time); intent.putExtra(EXTRA_IS_FINISHED, isFinished); sendBroadcast(intent); } // ... 其他原有代码 }
第二步:修改MainActivity的BroadcastReceiver,处理结束信号
让MainActivity收到计时结束的通知后,立刻更新按钮和输入框的状态:
public class MainActivity extends AppCompatActivity implements View.OnClickListener { // ... 其他原有代码 private BroadcastReceiver broadcastReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { String str_time = intent.getStringExtra("time"); tv_timer.setText(str_time); // 新增:处理计时结束的逻辑 boolean isFinished = intent.getBooleanExtra(Timer_Service.EXTRA_IS_FINISHED, false); if (isFinished) { // 恢复按钮和输入框的状态 btn_start.setEnabled(true); et_hours.setEnabled(true); // 如果你希望输入框也能重新编辑的话 // 清空SharedPreferences里的计时数据,避免下次打开还显示旧时间 mEditor.putString("data", "").commit(); mEditor.putBoolean("finish", false).commit(); } } }; // ... 其他原有代码 }
额外优化:处理Service意外销毁的情况
为了防止Service被系统回收导致状态不一致,建议在MainActivity的onResume里再做一次状态校验,确保按钮状态正确:
@Override protected void onResume() { super.onResume(); registerReceiver(broadcastReceiver,new IntentFilter(Timer_Service.str_receiver)); // 新增:校验计时状态,更新UI boolean isFinished = mpref.getBoolean("finish", false); String savedData = mpref.getString("data", ""); if (isFinished || savedData.isEmpty()) { btn_start.setEnabled(true); et_hours.setEnabled(true); tv_timer.setText(""); } else { btn_start.setEnabled(false); et_hours.setEnabled(false); tv_timer.setText(savedData); } }
这样修改后,当计时归0时,Service会立刻通知MainActivity启用按钮,同时修复了SharedPreferences的提交问题,就算Service意外崩溃,MainActivity在恢复前台时也会自动修正UI状态。
内容的提问来源于stack exchange,提问作者Hash
相关产品推荐
相关产品推荐

