10、WorkManager:WorkManager介绍、基本用法、链式任务、与JobScheduler的关系
各位同学,今天我们来聊聊WorkManager。说实话,这个组件是我在Android开发中越来越离不开的一个工具。你想想看,现在的App哪个不需要在后台干点活?上传日志、同步数据、定期清理缓存……这些任务如果处理不好,轻则被系统杀掉,重则被用户卸载。
WorkManager就是Google专门为解决这些问题推出的。它不是什么新东西,但它的设计思路,我个人觉得非常优雅。
WorkManager是什么?
简单说,WorkManager是一个用于可延迟、可靠的后台任务的API。注意这两个关键词:
- 可延迟:不要求立即执行,可以等网络好了、电量充足了再干
- 可靠:即使App被杀死、手机重启,任务也不会丢
我在项目中遇到过这样一个场景:用户拍照后需要上传原图。如果直接用Service,Android 8以后后台限制越来越严,经常被杀。用WorkManager就简单了——丢给它,它自己会找合适的时间上传,用户完全无感知。
核心特点:
- 兼容API 14+,不需要考虑版本适配
- 支持一次性任务和周期性任务
- 支持链式任务(串行/并行)
- 自带约束条件(网络、电量、存储等)
- 任务持久化,重启后继续执行
基本用法:三步搞定一个任务
WorkManager的使用流程非常清晰。我习惯把它分成三步:定义任务 → 配置约束 → 提交执行。
第一步:创建Worker类
Worker就是你的任务逻辑。继承Worker,重写doWork()方法:
class UploadWorker(context: Context, params: WorkerParameters) : Worker(context, params) {
override fun doWork(): Result {
// 这里写你的后台任务逻辑
val imageUri = inputData.getString("image_uri") ?: return Result.failure()
return try {
uploadImage(imageUri)
Result.success()
} catch (e: Exception) {
// 如果失败,可以重试
Result.retry()
}
}
}
嗯,这里要注意:doWork()是在后台线程执行的,所以你可以放心做网络请求、数据库操作。但千万别在这里做UI操作。
第二步:配置WorkRequest
WorkRequest是任务的"配置单"。你可以设置约束条件、输入数据、重试策略等:
val uploadRequest = OneTimeWorkRequestBuilder<UploadWorker>()
.setInputData(workDataOf("image_uri" to "/sdcard/photo.jpg"))
.setConstraints(
Constraints.Builder()
.setRequiredNetworkType(NetworkType.CONNECTED) // 需要网络
.setRequiresBatteryNotLow(true) // 电量不能太低
.build()
)
.setBackoffCriteria(
BackoffPolicy.EXPONENTIAL,
10, TimeUnit.SECONDS
)
.build()
我曾经踩过一个坑:没有设置重试策略,结果任务失败后直接放弃了。后来加上setBackoffCriteria,失败后指数退避重试,稳定多了。
第三步:提交给WorkManager
WorkManager.getInstance(context).enqueue(uploadRequest)
就这一行,剩下的交给系统。WorkManager会考虑各种约束条件,在合适的时候执行你的任务。
我的建议:如果任务需要用户等待结果,别用WorkManager。它适合"后台默默干活"的场景。需要即时反馈的,用Coroutine或RxJava更合适。
链式任务:让任务排队干活
实际项目中,任务往往不是孤立的。比如:先下载图片 → 压缩图片 → 上传图片。这三个步骤有先后依赖关系。
WorkManager的链式任务就是解决这个问题的。说白了,就是把多个任务串起来,一个接一个执行。
串行链:一个接一个
val download = OneTimeWorkRequestBuilder<DownloadWorker>().build()
val compress = OneTimeWorkRequestBuilder<CompressWorker>().build()
val upload = OneTimeWorkRequestBuilder<UploadWorker>().build()
WorkManager.getInstance(context)
.beginWith(download) // 第一个任务
.then(compress) // 第二个任务
.then(upload) // 第三个任务
.enqueue()
这样,download执行完才会执行compress,compress执行完才会执行upload。前一个任务的输出可以作为后一个任务的输入。
并行链:一起干
有时候任务之间没有依赖关系,可以同时执行。比如同时下载多张图片:
val download1 = OneTimeWorkRequestBuilder<DownloadWorker>().build()
val download2 = OneTimeWorkRequestBuilder<DownloadWorker>().build()
val download3 = OneTimeWorkRequestBuilder<DownloadWorker>().build()
WorkManager.getInstance(context)
.beginWith(listOf(download1, download2, download3)) // 并行执行
.then(uploadAll) // 都完成后执行这个
.enqueue()
你想想看,这种组合方式是不是很灵活?我在做一个相册备份功能时,就是先用并行链下载所有图片,再用串行链逐张上传。代码结构非常清晰。
注意:链式任务中,如果某个任务返回Result.failure(),整个链会终止。如果你希望失败后继续执行后面的任务,需要自己处理异常逻辑。
与JobScheduler的关系
很多同学会问:有了JobScheduler,为什么还要用WorkManager?
这个问题问得好。我简单梳理一下:
| 特性 | JobScheduler | WorkManager |
|---|---|---|
| 最低API版本 | API 21+ | API 14+ |
| 任务持久化 | 不支持(重启丢失) | 支持(Room持久化) |
| 链式任务 | 需要自己实现 | 原生支持 |
| 观察任务状态 | LiveData不支持 | 支持LiveData |
| 兼容性 | 不同厂商有差异 | 统一行为 |
说白了,WorkManager是JobScheduler的"升级版"。它底层会根据系统版本自动选择实现方式:
- API 23+:使用JobScheduler
- API 14-22:使用BroadcastReceiver + AlarmManager
你不需要关心这些细节,WorkManager帮你搞定了。我记得早期做项目时,为了兼容不同版本,我得写一堆if-else判断。现在一个WorkManager全搞定,省心多了。
一句话总结:如果你还在用JobScheduler,除非有特殊需求,否则我建议你迁移到WorkManager。它更现代、更强大、更省心。
知识体系总览
下面这张图是我整理的WorkManager核心知识结构,你可以对照着回顾一下:
好了,关于WorkManager的核心内容就这些。记住它的定位:可延迟、可靠的后台任务。下次遇到后台任务需求,先想想WorkManager能不能搞定。我个人经验是,90%的场景它都够用,而且比你自己手写Service+AlarmManager要靠谱得多。
避坑指南:我曾经在项目里用WorkManager做即时任务(比如用户点击按钮后立即发送请求),结果发现有时会有几秒延迟。后来才明白,WorkManager的设计初衷就不是"立即执行"。即时任务请用Coroutine或Thread,别让WorkManager背锅。