第2章 基础使用——调度一次性任务
2.1 原理概述
一次性任务(One‑Time Task)是 WorkManager 最基础的调度模式。App 只需定义任务逻辑、构建 OneTimeWorkRequest 并将其入队,WorkManager 便会自动在合适的时机——通常是立即或系统资源允许时——执行该任务。执行完成后任务状态变为 SUCCEEDED 或 FAILED,App 可通过 LiveData 观察状态变化。
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();
| 方法 | 作用 |
|---|---|
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,例如显示进度、结果或错误
}
});
| 返回值 | 最终状态 | 说明 |
|---|---|---|
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()取消未执行的任务,避免冗余调度。