第3章 Worker基本结构:CoroutineWorker与RxWorker选择、doWork方法定义、返回Result
3.1 Worker基本结构概述
WorkManager 中的 Worker 是任务执行的最小单元。Android 提供了三种 Worker 基类:Worker(同步)、CoroutineWorker(协程)和 RxWorker(RxJava)。在实际测试与生产环境中,由于网络请求(Retrofit)天然适合异步模型,我们主要关注后两种。本章聚焦 doWork() 方法的核心定义、返回结果类型以及如何根据项目异步栈选择 Worker 类型。
3.2 CoroutineWorker vs RxWorker 选择
两种 Worker 都将异步操作暴露给 WorkManager,但底层机制不同,直接影响测试写法与错误处理。
| 对比维度 | CoroutineWorker | RxWorker |
|---|---|---|
| 异步模型 | Kotlin 协程(suspend) | RxJava Observable/Single/Completable |
| doWork定义 | suspend fun doWork(): Result |
fun createWork(): Single<Result> |
| 适用场景 | 新项目、统一协程栈、Retrofit 挂起函数 | 遗留 RxJava 项目、已有 Response 流需要转换 |
| 错误处理 | try/catch 或 CoroutineExceptionHandler | RxJava onError 回调 |
| 重试机制 | 返回 Result.retry() 后自动重试 |
返回 Single.error(new RetryException()) 配合自定义策略 |
| 测试依赖 | kotlinx-coroutines-test, TestCoroutineDispatcher | RxJava TestObserver, TestScheduler |
选择建议:如果项目中 Retrofit 接口已使用
suspend fun,优先选择 CoroutineWorker,测试代码更简洁;若已大量使用 RxJava 进行响应式编排,则可继续使用 RxWorker 以保持一致性。
3.3 doWork 方法定义
两种 Worker 的 doWork 定义在语法上有明显差异,但语义相同:返回一个 Result 对象通知 WorkManager 任务状态。
3.3.1 CoroutineWorker
class SyncWorker(context: Context, params: WorkerParameters) : CoroutineWorker(context, params) {
override suspend fun doWork(): Result {
// 获取输入数据
val inputData = inputData.getString("KEY_URL") ?: return Result.failure()
return try {
// 假设 Retrofit 挂起函数
val response = apiService.fetchData(inputData)
// 处理成功逻辑
Result.success()
} catch (e: Exception) {
// 可重试的异常(如网络超时)
if (runAttemptCount < 3) {
Result.retry()
} else {
Result.failure()
}
}
}
}
3.3.2 RxWorker
class RxSyncWorker(context: Context, params: WorkerParameters) : RxWorker(context, params) {
override fun createWork(): Single<Result> {
val inputData = inputData.getString("KEY_URL") ?: return Single.just(Result.failure())
// 假设 apiService 返回 Single<Response>
return apiService.fetchDataRx(inputData)
.map { response ->
// 成功输出
Result.success()
}
.onErrorReturn { error ->
// 根据错误类型返回 retry 或 failure
if (runAttemptCount < 3) {
Result.retry()
} else {
Result.failure()
}
}
}
}
3.4 返回 Result 详解
Result 是 sealed 类,包含三种状态:
- Result.success():任务正常完成,WorkManager 不再重试。
- Result.failure():任务永久失败,WorkManager 不再重试,且会触发失败监听。
- Result.retry():任务需要重试。WorkManager 会根据
BackoffPolicy和runAttemptCount自动调度重试。
三种 Result 都不支持携带数据。若需要传递结果给下一个 Worker,必须使用 Result.success(outputData) 和 Data.Builder。
// 带输出数据的 Result(仅 CoroutineWorker 可用)
val output = workDataOf("RESULT_KEY" to "some value")
Result.success(output)
// RxWorker 通过 Single<Result> 返回,类似
Single.just(Result.success(workDataOf("KEY" to "val")))
常见错误:不要混淆
Result(WorkManager 返回类型)与 Kotlin 标准库的 kotlin.Result。WorkManager 的 Result 全限定名为 androidx.work.ListenableWorker.Result。代码中务必导入正确的包。
3.5 整体流程与生命周期
下图展示了一个 Worker 从创建到返回 Result 的完整生命周期,以及 Result 如何影响后续行为。
3.6 常见错误与调试
- 返回类型错误:CoroutineWorker 中若忘记 suspend 关键字,编译报错;RxWorker 若返回
Observable而非Single,WorkManager 无法正确订阅。 - 线程冲突:在 RxWorker 的
createWork()中做耗时操作未切换线程,会阻塞 Worker 调度线程,导致 ANR。 - 重试条件判断失效:没有检查
runAttemptCount就不断返回Result.retry(),造成无限重试。 - 测试中异步超时:使用 CoroutineWorker 测试时,未设置
TestCoroutineDispatcher的 advanceUntilIdle,导致测试阻塞。
调试技巧:在
doWork() 中通过 Log.d("Worker", "attempt=$runAttemptCount") 打印重试次数;使用 WorkManager 的 getWorkInfoByIdLiveData() 监听 Worker 状态变化。