WorkManager周期性任务如何编排多个工作请求顺序执行
WorkManager 顺序编排图片+表单同步任务实现
直接用WorkManager原生的任务链能力就能实现顺序执行,配合周期性工作请求满足2小时后台同步需求,不用自己写额外调度逻辑。
- 前置要求
你已经实现的两个Worker需要正确返回执行结果,这是任务链流转的核心依据:ImageUploadWorker:查询Room中待同步图片表,通过Retrofit Multipart完成上传后,将本地记录标记为已同步。遇到网络波动等临时错误返回Result.retry()触发退避重试,遇到图片损坏、服务端4xx错误等不可恢复问题返回Result.failure(),全部上传成功返回Result.success()。FormUploadWorker:查询Room待上报表单,关联已上传图片返回的服务端URL组装请求体提交,成功后标记本地表单为已同步,同样按错误类型返回对应Result。
注意:两个Worker统一使用传入的ApplicationContext,不要持有Activity/页面引用,避免内存泄漏。
- 单次手动触发的顺序编排
如果需要用户手动触发同步,直接用beginWith().then()链式调用即可,任务会严格按照传入顺序执行:
// 配置图片上传请求,加网络约束、重试策略 val imageUploadWork = OneTimeWorkRequestBuilder<ImageUploadWorker>() .setConstraints(Constraints.Builder() .setRequiredNetworkType(NetworkType.CONNECTED) .build()) .setBackoffCriteria(BackoffPolicy.EXPONENTIAL, 10, TimeUnit.SECONDS) .build() // 配置表单上传请求 val formUploadWork = OneTimeWorkRequestBuilder<FormUploadWorker>() .setConstraints(Constraints.Builder() .setRequiredNetworkType(NetworkType.CONNECTED) .build()) .setBackoffCriteria(BackoffPolicy.EXPONENTIAL, 10, TimeUnit.SECONDS) .build() // 编排执行顺序:先传图片,成功后再传表单 WorkManager.getInstance(context) .beginWith(imageUploadWork) .then(formUploadWork) .enqueue()
- 每2小时周期性同步的实现
注意PeriodicWorkRequest不能直接通过then()串联,推荐用入口Worker包装的方案实现周期顺序执行,稳定性最高:- 先写一个周期入口的CoroutineWorker,内部顺序等待两个子任务执行完成:
class PeriodicSyncWorker( appContext: Context, params: WorkerParameters ) : CoroutineWorker(appContext, params) { override suspend fun doWork(): Result { return try { // 先执行并等待图片上传完成 val imageTaskResult = WorkManager.getInstance(applicationContext) .enqueue(OneTimeWorkRequest.from(ImageUploadWorker::class.java)) .await() if (imageTaskResult.state != WorkInfo.State.SUCCEEDED) { return Result.retry() } // 图片上传成功后,再执行并等待表单上传完成 val formTaskResult = WorkManager.getInstance(applicationContext) .enqueue(OneTimeWorkRequest.from(FormUploadWorker::class.java)) .await() if (formTaskResult.state == WorkInfo.State.SUCCEEDED) Result.success() else Result.retry() } catch (e: Exception) { Result.retry() } } }
- 配置2小时间隔的周期性工作请求,注册唯一工作避免重复调度:
val periodicSyncRequest = PeriodicWorkRequestBuilder<PeriodicSyncWorker>( 2, TimeUnit.HOURS, // 执行间隔2小时 15, TimeUnit.MINUTES // 弹性时间窗口,适配系统Doze模式,最小不可低于15分钟 ) .setConstraints(Constraints.Builder() .setRequiredNetworkType(NetworkType.CONNECTED) .build()) .setBackoffCriteria(BackoffPolicy.EXPONENTIAL, 30, TimeUnit.SECONDS) .build() // 注册唯一周期任务,避免重复创建 WorkManager.getInstance(context) .enqueueUniquePeriodicWork( "app_full_data_sync", ExistingPeriodicWorkPolicy.KEEP, periodicSyncRequest )
- 关键注意事项
- 任务链的流转完全依赖前序任务的返回值:前序任务返回
failure()时后续任务不会执行,返回retry()时会按退避策略重试当前任务,直到成功/失败后才会继续流转,刚好匹配你「图片全部上传完成再传表单」的要求。 - 如果单批次图片上传量较大,建议给
ImageUploadWorker调用setForegroundAsync()配置前台服务通知,避免任务被系统后台限制杀死。 - 上传接口要做幂等校验:给每条本地图片、表单数据生成唯一UUID,随请求提交给服务端做去重,避免任务重试导致重复提交数据。
- 不要在两个Worker之间靠内存传递数据,需要跨任务传递的参数(比如上传成功的图片URL列表)要写入Room或者WorkManager的Data存储区,避免进程被杀后数据丢失。
- 任务链的流转完全依赖前序任务的返回值:前序任务返回
内容的提问来源于stack exchange,提问作者userVani
相关产品推荐
相关产品推荐

