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 实现演示同步逻辑,便于理解调度和结果返回机制。
Worker 集成 Retrofit 流程 WorkManager 调度 MyWorker 初始化 doWork() 执行 Retrofit 网络请求 结果处理 & 返回 Result.success/failure/retry 决定后续调度行为

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)