Android Periodic WorkManager每次打开应用触发、执行周期异常如何修复
Periodic WorkManager 执行异常修复方案
核心问题原因
- 每次启动应用重复入队新的定时任务:你在MainActivity.onCreate中每次都调用普通
enqueue方法,没有做任务去重,每打开一次应用就新增一个独立的15分钟定时任务,最终多个任务叠加导致执行频率异常、打开应用就触发任务。 - 异步任务未正确等待完成:
doWork方法中调用的FirebaseMessaging.getInstance().getToken()是异步接口,你在回调还没执行完成的时候就直接返回了Result.success(),WorkManager会判定任务已结束,一方面可能导致实际逻辑未执行完成,另一方面可能触发异常重试机制,打乱正常调度周期。
修复步骤
1. 修改MainActivity中的任务入队逻辑
使用enqueueUniquePeriodicWork代替普通入队方法,为任务指定唯一标识,避免重复创建同类型任务:
Constraints constraints = new Constraints.Builder() .setRequiredNetworkType(NetworkType.CONNECTED) .setRequiresBatteryNotLow(true) .build(); PeriodicWorkRequest periodicWorkRequest = new PeriodicWorkRequest.Builder( UpdateUserDataService.class, 15, TimeUnit.MINUTES) .setConstraints(constraints) .build(); // 唯一任务入队,第一个参数为自定义的唯一任务名,第二个参数指定如果已有同名任务则保留原有任务 WorkManager.getInstance(this) .enqueueUniquePeriodicWork("update_user_data_periodic", ExistingPeriodicWorkPolicy.KEEP, periodicWorkRequest);
2. 修改Worker的异步逻辑,等待任务执行完成再返回结果
在doWork中同步等待Firebase异步操作完成,再返回执行结果,避免任务提前结束(doWork默认运行在后台线程,阻塞操作不会影响主线程):
public class UpdateUserDataService extends Worker { public UpdateUserDataService(@NonNull Context context, @NonNull WorkerParameters workerParams) { super(context, workerParams); } @RequiresApi(api = Build.VERSION_CODES.O) @NonNull @Override public Result doWork() { try { // 同步等待获取token完成 String token = Tasks.await(FirebaseMessaging.getInstance().getToken()); DatabaseReference reference = FirebaseDatabase.getInstance().getReference("Update"); SimpleDateFormat dateFormat = new SimpleDateFormat("dd-MMM-yyyy_h:mm a", Locale.getDefault()); Calendar c = Calendar.getInstance(); String currentDate = dateFormat.format(c.getTime()); JobFooter jobFooter = new JobFooter(currentDate, token); // 同步等待数据库写入完成 Tasks.await(reference.child(dateFormat.format(new Date())).setValue(jobFooter)); Uri defaultSoundUri = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION); Intent notificationIntent = new Intent(getApplicationContext(), MainActivity.class); notificationIntent.putExtra("Notification", true); notificationIntent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_SINGLE_TOP); PendingIntent intent = PendingIntent.getActivity(getApplicationContext(), 0, notificationIntent, PendingIntent.FLAG_UPDATE_CURRENT); NotificationHelper notificationHelper = new NotificationHelper(getApplicationContext(), defaultSoundUri); Notification.Builder notificationBuilder = notificationHelper.getNotification("Title", currentDate, intent); notificationHelper.notify(10, notificationBuilder); return Result.success(); } catch (ExecutionException | InterruptedException e) { e.printStackTrace(); // 执行失败返回重试,WorkManager会自动按照退避策略重试 return Result.retry(); } } }
注意事项
- 15分钟是Android系统限定的PeriodicWorkRequest最小间隔,系统为了优化节电会对定时任务进行批量调度,实际执行时间可能有少量延迟,属于符合系统规范的正常现象。
- 任务一旦成功入队,只要应用没有被用户强行停止,就算应用不在前台也会按照设定周期执行。
内容的提问来源于stack exchange,提问作者Ankit Verma
相关产品推荐
相关产品推荐

