WorkManager 集成 Retrofit:Worker 类创建与同步逻辑实现
后台同步任务的核心是将 WorkManager 的调度能力与 Retrofit 的网络请求能力结合。本章从零实现一个标准的同步 Worker:包含类定义、依赖注入、doWork() 中的同步逻辑以及结果返回处理。
4.1 原理概述
WorkManager 在后台线程中调用 Worker 的 doWork() 方法,该方法内执行同步网络请求并返回 Result。集成 Retrofit 的关键步骤:
- 创建 Worker 子类:继承
Worker或CoroutineWorker,通过构造函数接收 Retrofit 实例。 - 注入 Retrofit 实例:利用 Hilt / Dagger 的
@HiltWorker注解或手动依赖注入。 - 同步逻辑:在
doWork()中调用 Retrofit 接口方法,解析响应。 - 结果处理:根据网络请求成功/失败状态返回
Result.success()、Result.failure()或Result.retry()。
提示:推荐使用
CoroutineWorker + 协程方式避免线程阻塞,但本课程以经典 Worker 实现演示同步逻辑,便于理解调度和结果返回机制。
4.2 创建 Worker 类与注入 Retrofit
创建一个继承 Worker 的类,通过构造函数接收 Retrofit 实例。使用 Hilt 的 @HiltWorker 注解实现依赖注入。
@HiltWorker
class SyncWorker @AssistedInject constructor(
@Assisted context: Context,
@Assisted workerParams: WorkerParameters,
private val retrofit: Retrofit
) : Worker(context, workerParams) {
override fun doWork(): Result {
// 同步网络逻辑
}
}
如果项目未使用 Hilt,可以通过 WorkerFactory 手动注入:
class SyncWorkerFactory(
private val retrofit: Retrofit
) : WorkerFactory() {
override fun createWorker(
appContext: Context,
workerClassName: String,
workerParameters: WorkerParameters
): ListenableWorker? {
return SyncWorker(appContext, workerParameters, retrofit)
}
}
4.3 doWork() 中的同步逻辑实现
doWork() 在后台线程执行,可以安全调用阻塞式网络请求。下面是一个同步逻辑的完整示例:
private val api: SyncApi = retrofit.create(SyncApi::class.java)
override fun doWork(): Result {
return try {
val response = api.syncData().execute() // 同步请求
if (response.isSuccessful && response.body() != null) {
val syncResult = response.body()!!
// 处理同步数据,例如写入本地数据库
LocalDataStore.save(syncResult)
Result.success()
} else {
// 服务器返回错误码,标记重试
Result.retry()
}
} catch (e: IOException) {
// 网络异常,请求重试
Result.retry()
} catch (e: Exception) {
// 其他未知异常,视为永久失败
Result.failure()
}
}
注意:
execute() 是同步调用,必须在后台线程执行。使用 CoroutineWorker 时改用 await() 避免线程阻塞。确保 API 接口返回类型为 Response<T> 以便处理 HTTP 状态码。
4.4 返回结果处理策略
返回的 Result 类型直接影响 WorkManager 的后续行为,下表列出三种返回值的使用场景:
| Result 类型 | 含义 | WorkManager 行为 | 典型使用场景 |
|---|---|---|---|
Result.success() |
任务成功完成 | 标记为完成,不再重试 | 数据已成功同步到服务器 |
Result.failure() |
任务永久失败 | 标记为失败,不再调度 | 服务器返回 400/500 且重试无意义 |
Result.retry() |
任务需要重试 | 进入退避策略队列,按配置重试 | 网络超时、服务临时错误 |
退避策略可以通过 BackoffPolicy 配置:
val syncRequest = OneTimeWorkRequestBuilder<SyncWorker>()
.setBackoffCriteria(
BackoffPolicy.EXPONENTIAL,
WorkRequest.MIN_BACKOFF_MILLIS,
TimeUnit.MILLISECONDS
)
.build()
4.5 调试与常见错误
集成过程中的典型问题及解决方案:
- 错误:Retrofit 实例为 null —— 检查 Hilt 模块是否正确绑定
Retrofit提供者,或手动工厂注入时确保工厂已注册。 - 错误:doWork() 抛出 NetworkOnMainThreadException —— 确认测试时 Worker 是否在后台线程执行;使用
WorkManagerTestInitHelper模拟后台环境。 - 错误:Result.retry() 未被调用 —— 确认 WorkManager 版本 ≥ 2.7.0,且未在
doWork()中捕获所有异常导致未返回 retry。
性能提示:如果同步数据量大,建议在
doWork() 中分批进行请求,避免单次请求占用过长时间。通过 setExpedited() 标记紧急同步任务,系统将尽力快速执行(Android 12+ 需声明前台服务类型)。
4.6 稳定性优化建议
- 使用
setConstraints()添加网络约束条件,确保在 Wi-Fi 下进行大数据量同步。 - 在
doWork()中实现幂等性逻辑:如果数据已同步,直接返回Result.success()避免重复请求。 - 对于关键数据,结合
OutputData将同步状态传递给后续观察者:
val outputData = workDataOf("sync_status" to "completed")
Result.success(outputData)