2. 定义第一个 Worker 与 WorkRequest
本章进入实际操作 —— 创建第一个 Worker 实现类,构建对应的 OneTimeWorkRequest,并通过 WorkManager.enqueue() 将任务提交到调度系统。这是使用 WorkManager 链式调度的起点,后续所有复杂的任务依赖、约束、重试策略都建立在这一基本流程之上。
2.1 原理:Worker 的抽象与 WorkRequest 的封装
- Worker 类:继承自
androidx.work.Worker,必须重写doWork()方法。该方法在后台线程执行,返回Result.success()、Result.failure()或Result.retry(),代表任务执行结果。 - WorkRequest:对 Worker 的封装,携带执行约束(如网络条件、电量)、重试策略、输入数据等。
OneTimeWorkRequest表示一次性任务,适用于大部分链式调度场景。 - enqueue:将 WorkRequest 提交到 WorkManager 的 JobScheduler / AlarmManager 队列中,实际调度由系统根据约束和优先级触发。
2.2 实现流程
- 创建
Worker子类,实现doWork()方法。 - 在
doWork()中编写具体后台任务逻辑,返回Result。 - 使用
OneTimeWorkRequest.Builder(YourWorker::class.java)构建WorkRequest。 - 可选:通过
.setConstraints()设置网络、电量等约束。 - 通过
WorkManager.getInstance(context).enqueue(workRequest)提交任务。
2.3 代码实现
定义 Worker 子类
class DataSyncWorker(context: Context, workerParams: WorkerParameters) :
Worker(context, workerParams) {
override fun doWork(): Result {
// 模拟后台数据同步
return try {
val inputData = inputData.getString("key_url") ?: ""
// 执行网络请求或数据库操作
Thread.sleep(2000) // 模拟耗时
Result.success()
} catch (e: Exception) {
Result.retry()
}
}
}
构建 OneTimeWorkRequest 并提交
// 创建约束:需要网络连接
val constraints = Constraints.Builder()
.setRequiredNetworkType(NetworkType.CONNECTED)
.build()
// 构建一次性工作请求
val syncRequest = OneTimeWorkRequestBuilder<DataSyncWorker>()
.setConstraints(constraints)
.setInputData(workDataOf("key_url" to "https://example.com/sync"))
.addTag("sync_task")
.build()
// 提交任务
WorkManager.getInstance(applicationContext).enqueue(syncRequest)
关键点:OneTimeWorkRequestBuilder 支持链式设置,setInputData 传递参数给 Worker,addTag 用于后续观察或取消指定任务。
2.4 调试与验证
- 在
doWork()中加入日志输出:Log.d("WorkManager", "任务开始,输入URL: $url") - 观察
Logcat中WorkManager标签的日志,确认任务被调度、执行、完成。 - 使用
WorkManager.getWorkInfoByIdLiveData(workRequest.id)监听任务状态。
调试技巧:在开发者选项中开启“不保留活动”或使用模拟器测试后台限制,观察 WorkManager 在进程被杀死后能否重试。
2.5 常见错误及解决
| 错误场景 | 可能原因 | 解决方法 |
|---|---|---|
| 任务从未执行 | 约束未满足(如无网络)或系统延迟调度 | 检查约束设置,可临时移除约束测试 |
doWork 抛出异常 |
未捕获异常导致 Worker 默认返回 failure | 在 doWork 中使用 try-catch 并显式返回 Result |
| 输入数据为空 | inputData.getString() 的 key 拼写错误 |
检查 key 与 workDataOf 中的 key 是否一致 |
| 重复提交相同任务 | 每次创建新的 WorkRequest 导致多个实例 | 使用 beginUniqueWork 或去重逻辑 |
2.6 性能与稳定性建议
- 最小化
doWork耗时:WorkManager 默认有 10 分钟执行超时(Android 12+ 缩短),耗时任务应分割为多个链式 Worker。 - 合理使用
Result.retry():配合setBackoffCriteria设置退避策略,避免无限制重试。 - 避免在主线程调用
enqueue:虽然enqueue本身安全,但建议在 ViewModel 或异步上下文中操作。
注意:若 Worker 需要访问 Application 级别单例,请使用 getApplicationContext() 而非 WeakReference,确保 Worker 生命周期内引用有效。