WorkManager 基础概念与 API 入门

WorkManager 是 Android Jetpack 中用于可延迟、可保证执行的后台任务调度库。它与应用生命周期深度集成,即使应用被杀死或设备重启,任务也会在合适时机恢复执行。本章围绕 Worker、WorkRequest、WorkManager.getInstance() 以及任务调度与状态观察四个核心 API,梳理其原理、实现流程与常见陷阱。

核心思想:WorkManager 将任务定义(Worker)、任务配置(WorkRequest)与任务调度(WorkManager)分离,并通过 LiveData 或 Flow 提供可观察的状态更新。
WorkManager 任务调度与状态观察流程 Worker doWork() → Result WorkRequest 约束 / 重试 / 输入数据 WorkManager getInstance().enqueue() 内部任务队列 顺序 + 优先级 状态观察 LiveData / Flow Result.success() Result.retry() Result.failure() 继承 & 封装 enqueue() 状态变更通知

1. Worker 基类:任务定义单元

所有后台任务都需要继承 Worker 类并重写 doWork() 方法。该方法运行在 WorkManager 提供的后台线程上,返回 Result 以告知调度器任务是否成功。Worker 是单次执行模型,如果需要周期性任务则使用 PeriodicWorkRequest。

Result 类型含义重试行为
Result.success()任务正常完成不重试
Result.retry()任务需重试(受重试策略控制)按退避策略重试
Result.failure()任务失败,不再重试不重试
class UploadWorker(context: Context, params: WorkerParameters) : Worker(context, params) {
    override fun doWork(): Result {
        val inputData = inputData.getString("file_path") ?: return Result.failure()
        return try {
            uploadFile(inputData)
            Result.success()
        } catch (e: IOException) {
            Result.retry()
        }
    }
}

2. WorkRequest:任务描述与配置

WorkRequest 封装 Worker 与运行时配置(约束、重试策略、输入数据、标签等)。主要分为两种:

类型创建方式执行次数最小间隔
OneTimeWorkRequestOneTimeWorkRequestBuilder<Worker>()1 次无
PeriodicWorkRequestPeriodicWorkRequestBuilder<Worker>(15, TimeUnit.MINUTES)多次(周期性)≥ 15 分钟(实际间隔来自后台限制)
val uploadRequest = OneTimeWorkRequestBuilder<UploadWorker>()
    .setInputData(workDataOf("file_path" to "/sdcard/tmp.txt"))
    .setConstraints(
        Constraints.Builder()
            .setRequiredNetworkType(NetworkType.CONNECTED)
            .build()
    )
    .setBackoffCriteria(BackoffPolicy.EXPONENTIAL, 10, TimeUnit.SECONDS)
    .addTag("upload")
    .build()
使用 setBackoffCriteria() 控制重试间隔:默认线性退避,建议关键任务使用指数退避以减少服务器压力。

3. WorkManager 实例与任务提交

WorkManager.getInstance() 返回全局单例,无需手动初始化(应用启动时自动通过 ContentProvider 初始化)。调用 enqueue() 将 WorkRequest 提交到内部队列。

val workManager = WorkManager.getInstance(context)
workManager.enqueue(uploadRequest)

也可使用 enqueueUniqueWork() 或 beginUniqueWork() 进行链式任务编排。

4. 任务状态与实时观察

通过 getWorkInfoByIdLiveData() 获取 LiveData<WorkInfo>,观察状态变化。WorkInfo 包含:

  • State:ENQUEUED、RUNNING、SUCCEEDED、FAILED、CANCELLED、BLOCKED
  • outputData:Worker 通过 Result.success(outputData) 传回结果
  • tags:关联的标签集合
workManager.getWorkInfoByIdLiveData(uploadRequest.id)
    .observe(viewLifecycleOwner) { workInfo: WorkInfo ->
        when (workInfo.state) {
            WorkInfo.State.SUCCEEDED -> { /* 处理成功 */ }
            WorkInfo.State.FAILED    -> { /* 处理失败 */ }
            else -> { /* 其他状态 */ }
        }
    }
状态观察必须在主线程注册(LiveData 自动保证),但 doWork() 中切勿直接更新 UI,应通过状态观察回调或共享 ViewModel 传递结果。

5. 调试方法与常见陷阱

  • 启用调试日志:在 AndroidManifest.xml 中添加 <meta-data android:name="androidx.work.util.Logging" android:value="INFO" /> 或在 Application.onCreate() 中调用 Logging.setLoggingCallback。
  • 约束不满足导致不执行:例如网络约束或存储约束未达到,任务会一直处于 ENQUEUED 状态。使用 WorkManager.getWorkInfosByTagLiveData(tag) 观察可排查。
  • 重试策略误用:Result.retry() 配合 BackoffPolicy.LINEAR 可能造成频繁重试,建议使用 EXPONENTIAL 并设置合理初始延迟(默认 30 秒)。
  • Worker 中的静态状态:Worker 实例在每次调度时重新创建,不要在 Worker 中持有 Activity 或 View 引用,否则导致内存泄漏。

6. 性能考量与最佳实践

  • doWork() 保持轻量:系统会给 Worker 分配一个后台线程,但长时间阻塞(如 > 10 秒)可能被系统视为 ANR 或延迟其他任务。网络请求、文件操作应使用异步 I/O 或考虑使用 CoroutineWorker(后续章节展开)。
  • 合理使用约束:只设置必要的约束(如 NetworkType.CONNECTED),避免过度约束导致任务迟迟不执行。
  • 数据合并:当多个 WorkRequest 输出到同一链式任务时,使用 InputMerger(如 ArrayCreatingInputMerger)避免数据覆盖。
  • 避免重复 enqueue:使用 enqueueUniqueWork(ExistingWorkPolicy.KEEP) 防止相同标识的任务重复入队。