第2章 基础使用——调度一次性任务

2.1 原理概述

一次性任务(One‑Time Task)是 WorkManager 最基础的调度模式。App 只需定义任务逻辑、构建 OneTimeWorkRequest 并将其入队,WorkManager 便会自动在合适的时机——通常是立即或系统资源允许时——执行该任务。执行完成后任务状态变为 SUCCEEDED 或 FAILED,App 可通过 LiveData 观察状态变化。

一次性任务调度流程 Android App 自定义 Worker OneTimeWorkRequest.Builder WorkManager.enqueue() WorkManager 内部调度 (约束检查、延迟、线程池) doWork() 执行 LiveData 状态 (UI 层) 一次性任务生命周期 ENQUEUED → RUNNING → SUCCEEDED / FAILED

2.2 创建自定义 Worker

继承 Worker 类,重写 doWork() 方法。该方法在 WorkManager 的后台线程中执行,返回 Result 标示执行结果:

public class UploadWorker extends Worker {
    public UploadWorker(@NonNull Context context, @NonNull WorkerParameters params) {
        super(context, params);
    }

    @NonNull
    @Override
    public Result doWork() {
        // 执行实际任务(例如上传文件)
        boolean success = performUpload();
        return success ? Result.success() : Result.failure();
    }
}
注意: doWork() 是在 WorkManager 提供的后台线程中运行的,这里可以直接执行同步代码;但绝不能在此方法中执行长期阻塞操作(如网络请求不设超时),否则可能导致任务被系统强制终止。

2.3 构造 OneTimeWorkRequest

使用 OneTimeWorkRequest.Builder 构建任务请求,可设置延迟、约束、输入数据等:

OneTimeWorkRequest uploadRequest =
        new OneTimeWorkRequest.Builder(UploadWorker.class)
                .setInitialDelay(10, TimeUnit.SECONDS)   // 延迟10秒执行
                .addTag("upload")
                .setInputData(new Data.Builder()
                        .putString("file_uri", fileUri.toString())
                        .build())
                .build();
OneTimeWorkRequest.Builder 常用方法
方法作用
setInitialDelay()设置任务首次执行的延迟时间
addTag()为任务添加标签,便于批量取消或观察
setInputData()传递输入数据给 Worker(通过 getInputData() 获取)
setConstraints()设置执行约束(如网络状态、电量等)
setBackoffCriteria()设置重试退避策略(仅当返回 RETRY 时生效)

2.4 将任务 enqueue 到 WorkManager

通过 WorkManager.getInstance(context) 获取实例,调用 enqueue() 提交任务:

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

也可以使用 enqueueUniqueWork() 确保同名任务唯一性,但本章仅聚焦基本用法。

常见错误: 忘记调用 WorkManager.initialize() 或在 Application 中未正确配置。如果使用默认初始化(通过 ContentProvider 自动完成),只需确保应用依赖 WorkManager 即可。若自定义配置,请在 Application.onCreate() 中先初始化。

2.5 观察任务状态 LiveData

WorkManager 提供了 getWorkInfoByIdLiveData(UUID) 返回 LiveData<WorkInfo>,UI 层可安全观察:

UUID workId = uploadRequest.getId(); // 从构建的 Request 中获得
LiveData<WorkInfo> workInfoLiveData =
        WorkManager.getInstance(context).getWorkInfoByIdLiveData(workId);

workInfoLiveData.observe(this, workInfo -> {
    if (workInfo != null) {
        WorkInfo.State state = workInfo.getState();
        // 根据 state 更新 UI,例如显示进度、结果或错误
    }
});
Worker 返回值与对应状态
返回值最终状态说明
Result.success()SUCCEEDED任务正常完成
Result.failure()FAILED任务执行失败,不自动重试
Result.retry()ENQUEUED(重试)请求重试,根据退避策略再次入队

2.6 运行测试

在模拟器或真机上运行应用,观察 Logcat 或 UI 状态:

// 在 Worker 的 doWork() 中添加日志
Log.d("UploadWorker", "doWork start");
// ... 任务逻辑 ...
Log.d("UploadWorker", "doWork end, result: " + success);

执行流程:应用启动 → 调用 enqueue → 查看 Logcat 中日志输出(可在 10 秒延迟后出现)。建议使用 WorkManagerTestInitHelper 进行单元测试,但本章仅验证基本流程。

调试技巧: 使用 adb shell dumpsys jobscheduler 可以查看系统 JobScheduler(WorkManager 的底层)的任务状态,确认任务是否被正确调度。

2.7 常见错误与调试

  • Worker 未注册或未构建:确保在 OneTimeWorkRequest.Builder 中传入的 Worker 类存在且构造方法正确(两参数构造器)。
  • doWork() 返回 null:必须返回非 null 的 Result,否则抛出异常。
  • enqueue 后任务不执行:检查约束是否满足(如网络约束在无网状态下不会触发),或检查应用进程是否被杀死(WorkManager 保证重启后重试)。
  • LiveData 不更新:确认 observe() 调用在拥有有效 LifecycleOwner 的线程(通常为 UI 线程),且没有调用 removeObserver。
  • 初始延迟无效:延迟时间不能小于 10 秒(系统最小间隔),若设置 5 秒实际可能被延迟到 10 秒后;但此限制在 Android 12+ 有所放宽。

2.8 性能与稳定性优化

  • 避免在 doWork() 中执行长时间任务:一次性任务默认在 10 分钟内必须返回结果,否则系统会视其为“超时”并将任务标记为失败。若确有长时间操作,改用 ListenableWorker 配合协程或 RxJava。
  • 合理使用 setBackoffCriteria():当 doWork() 返回 RETRY 时,通过重试策略控制间隔,避免频繁重试耗尽资源。
  • 输入数据尽量轻量:Data 对象大小有限制(约 10KB),大型数据应通过文件路径或 Room 数据库传递。
  • 观察 LiveData 时注意内存泄漏:在 Fragment/Activity 销毁时自动解除观测,若使用自定义 LifecycleOwner 需手动管理。
  • 使用 addTag 管理批量任务:便于调用 WorkManager.cancelAllWorkByTag() 取消未执行的任务,避免冗余调度。