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 队列中,实际调度由系统根据约束和优先级触发。
第一个 Worker 提交流程 定义 Worker 子类 构建 OneTimeWorkRequest 添加 Constraints WorkManager.enqueue() 系统等待约束满足 Worker.doWork() 执行 返回 success/failure/retry 说明:Worker 的 doWork() 在后台线程执行,非主线程;WorkRequest 的构建可链式调用设置输入数据。

2.2 实现流程

  1. 创建 Worker 子类,实现 doWork() 方法。
  2. 在 doWork() 中编写具体后台任务逻辑,返回 Result。
  3. 使用 OneTimeWorkRequest.Builder(YourWorker::class.java) 构建 WorkRequest。
  4. 可选:通过 .setConstraints() 设置网络、电量等约束。
  5. 通过 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 生命周期内引用有效。