如何实现App关闭后仍运行的后台Timer?附代码求正确实现
搞定App后台运行定时器的问题
嘿,我仔细看了你的代码,发现几个关键问题导致Service里的定时器没正常工作,咱们一步步把它修好:
1. 别用静态变量传参数,太不靠谱!
你现在靠page2里的静态myVariable给Service传时长,这真的不行——Fragment销毁后(比如切后台、换页面),这个变量很可能失效或者值不对。正确姿势是用Intent带参数:
在page2的startService方法里改成这样:
public void startService(int duration) { Intent intent = new Intent(getActivity(), MyService.class); intent.putExtra("TIMER_DURATION", duration); // 把时长打包进Intent getActivity().startService(intent); }
然后在MyService的onStartCommand里取参数:
@Override public int onStartCommand(Intent intent, int flags, int startId) { if (intent != null) { int duration = intent.getIntExtra("TIMER_DURATION", 0); // 给个默认值防崩溃 if (duration > 0) { setParam(duration); // 终于启动定时器了! Toast.makeText(this, "后台定时器已启动,时长:" + duration + "ms", Toast.LENGTH_LONG).show(); } } return START_STICKY; }
2. 你之前根本没在Service里启动定时器!
看你原来的onStartCommand,只是弹了个Toast,完全没调用setParam方法——这就是定时器没运行的直接原因!上面的代码已经补上了这个调用。
3. 把振动和定时器逻辑补全
首先,振动需要权限,记得在AndroidManifest.xml里加:
<uses-permission android:name="android.permission.VIBRATE" />
然后把Service里的定时器和振动逻辑改得更靠谱:
private Vibrator v; // 定时器核心方法 public void setParam(int param) { CountDownTimer countDownTimer = new CountDownTimer(param, 1000) { @Override public void onTick(long millisUntilFinished) { // 要是想给前台Fragment更改进度,得用广播或者EventBus,Service不能直接碰UI // 后台计时的话,这里留空或者打个日志就行 } @Override public void onFinish() { // 倒计时结束,震起来! triggerVibration(); // 任务完成,自己停掉Service stopSelf(); } }; countDownTimer.start(); } // 振动实现 private void triggerVibration() { long[] pattern = {50, 1000, 500, 1000, 500, 1000, 500, 1000, 500, 1000, 500, 1000, 500, 1000, 500, 1000, 500, 1000}; v = (Vibrator) getSystemService(Context.VIBRATOR_SERVICE); if (v != null) { v.vibrate(pattern, -1); Toast.makeText(this, "倒计时结束啦!", Toast.LENGTH_LONG).show(); } }
4. 应对系统杀后台的情况
Android系统资源紧张时,后台Service很容易被干掉。想让定时器尽量活下去,可以做这两点:
- 你已经用了
START_STICKY,这个不错,Service被杀死后系统会尝试重启,但重启时Intent会是null,所以咱们的代码里加了判空处理 - Android 8.0及以上对后台Service限制很严,建议把Service改成前台Service,启动时弹个通知:
在MyService里加前台通知的代码(记得准备个通知图标):
private static final int NOTIFICATION_ID = 1001; @Override public int onStartCommand(Intent intent, int flags, int startId) { // ... 前面的参数获取和定时器启动代码 ... // 前台Service通知(Android 8.0+必须) NotificationCompat.Builder builder = new NotificationCompat.Builder(this, "TIMER_CHANNEL") .setContentTitle("后台定时器") .setContentText("正在倒计时中...") .setSmallIcon(R.drawable.ic_timer_notification); // 换成你的图标资源 // Android 8.0+需要创建通知渠道 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { NotificationChannel channel = new NotificationChannel("TIMER_CHANNEL", "定时器通知", NotificationManager.IMPORTANCE_LOW); NotificationManager manager = getSystemService(NotificationManager.class); if (manager != null) { manager.createNotificationChannel(channel); } } startForeground(NOTIFICATION_ID, builder.build()); return START_STICKY; }
最后,清理Fragment里的冗余代码
你在page2里也写了一个CountDownTimer,这会导致前台后台同时跑两个定时器,建议把Fragment里的setParam方法删掉,只保留启动Service的逻辑,所有计时都交给Service处理。
这样改完之后,就算把App关掉(不是强制杀死进程),Service里的定时器也会继续跑,到点就振动提醒啦!
内容的提问来源于stack exchange,提问作者jnrx gaming
相关产品推荐
相关产品推荐

