(两百六十五)学习使用 WorkManager 调度任务
学习https://developer.android.google.cn/topic/libraries/architecture/workmanager/basics
使用 WorkManager 调度任务
使用 WorkManager API 可以轻松地调度即使在应用退出或设备重启时仍应运行的可延迟异步任务。
主要功能:
- 最高向后兼容到 API 14
- 在运行 API 23 及以上级别的设备上使用 JobScheduler
- 在运行 API 14-22 的设备上结合使用 BroadcastReceiver 和 AlarmManager
- 添加网络可用性或充电状态等工作约束
- 调度一次性或周期性异步任务
- 监控和管理计划任务
- 将任务链接起来
- 确保任务执行,即使应用或设备重启也同样执行任务
- 遵循低电耗模式等省电功能
WorkManager 旨在用于可延迟运行(即不需要立即运行)并且在应用退出或设备重启时必须能够可靠运行的任务。例如:
- 向后端服务发送日志或分析数据
- 定期将应用数据与服务器同步
WorkManager 不适用于应用进程结束时能够安全终止的运行中后台工作,也不适用于需要立即执行的任务。请查看后台处理指南,了解哪种解决方案符合您的需求。
兼容API23之下的意义不是很大了,现在都到Android R了,API 22还是L,5年前的机型了,可以认为现在主流机型的内部实现应该是用的JobScheduler。亮点暂时看到的是可重启、加约束和低功耗
WorkManager 入门指南
通过 WorkManager,您可以轻松设置任务并提交给系统,以在您指定的条件下运行。如需进一步了解 WorkManager 是不是适合您任务的解决方案,请参阅后台处理指南。
在本指南中,您将了解到如何执行以下操作:
- 将 WorkManager 添加到您的 Android 项目中
- 创建后台任务
- 配置运行任务的方式和时间
- 将任务提交给系统
要了解 WorkManager 功能(例如处理周期性工作、创建工作链以及取消工作),请参阅方法指南。
将 WorkManager 添加到您的 Android 项目中
按照 WorkManager 版本说明中的说明,使用 Java 或 Kotlin 语言将 WorkManager 依赖项添加到您的 Android 项目中。
https://developer.android.google.cn/jetpack/androidx/releases/work#declaring_dependencies
声明依赖项
如需添加 WorkManager 的依赖项,您必须将 Google Maven 代码库添加到项目中:
在应用或模块的 build.gradle 文件中添加所需工件的依赖项:
dependencies {
def work_version = "2.3.4"
// (Java only)
implementation "androidx.work:work-runtime:$work_version"
// Kotlin + coroutines
implementation "androidx.work:work-runtime-ktx:$work_version"
// optional - RxJava2 support
implementation "androidx.work:work-rxjava2:$work_version"
// optional - GCMNetworkManager support
implementation "androidx.work:work-gcm:$work_version"
// optional - Test helpers
androidTestImplementation "androidx.work:work-testing:$work_version"
}
创建后台任务
任务是使用 Worker
类定义的。doWork()
方法在 WorkManager 提供的后台线程上同步运行。
要创建后台任务,请扩展 Worker
类并替换 doWork()
方法。例如,要创建上传图像的 Worker
,您可以执行以下操作:
public class UploadWorker extends Worker {
public UploadWorker(
@NonNull Context context,
@NonNull WorkerParameters params) {
super(context, params);
}
@Override
public Result doWork() {
// Do the work here--in this case, upload the images.
uploadImages()
// Indicate whether the task finished successfully with the Result
return Result.success()
}
}
从 doWork()
返回的 Result
会通知 WorkManager 任务是否:
- 已成功完成:
Result.success()
- 已失败:
Result.failure()
- 需要稍后重试:
Result.retry()
注意:Worker
是运行工作的最简单方式。要了解 Worker 的更多高级选项,请参阅 WorkManager 线程指南。
配置运行任务的方式和时间
Worker
定义工作单元,WorkRequest
则定义工作的运行方式和时间。任务可以是一次性的,也可以是周期性的。对于一次性 WorkRequest
,请使用 OneTimeWorkRequest
,对于周期性工作,请使用 PeriodicWorkRequest
。要详细了解如何调度周期性工作,请参阅周期性工作文档。
在本例中,为 UploadWorker 构建 WorkRequest
最简单的示例为:
OneTimeWorkRequest uploadWorkRequest = new OneTimeWorkRequest.Builder(UploadWorker.class) .build()
WorkRequest
中还可以包含其他信息,例如任务在运行时应遵循的约束、工作输入、延迟,以及重试工作的退避时间政策。关于这些选项,在定义工作指南中有更详细的说明。
将您的任务提交给系统
定义 WorkRequest
之后,您现在可以通过 WorkManager
使用 enqueue()
方法来调度它。
WorkManager.getInstance(myContext).enqueue(uploadWorkRequest);
执行 Worker 的确切时间取决于 WorkRequest
中使用的约束以及系统优化。WorkManager 的设计目的就是要在这些限制下提供尽可能好的表现。
定义工作请求
入门指南介绍了如何创建简单的 WorkRequest
并将其加入队列。
在本指南中,您将了解如何自定义工作请求来处理常见用例:
- 处理网络可用性等任务约束
- 确保任务延迟一定时间再执行
- 处理任务重试和退避
- 处理任务输入和输出
- 使用标记对任务进行分组
工作约束
您可以向工作添加
Constraints
,以指明工作何时可以运行。例如,您可以指定工作应仅在设备空闲且接通电源时运行。
下面的代码展示了如何将这些约束添加到
OneTimeWorkRequest
。有关所支持约束的完整列表,请参阅Constraints.Builder
参考文档。// Create a Constraints object that defines when the task should run Constraints constraints = new Constraints.Builder() .setRequiresDeviceIdle(true) .setRequiresCharging(true) .build(); // ...then create a OneTimeWorkRequest that uses those constraints OneTimeWorkRequest compressionWork = new OneTimeWorkRequest.Builder(CompressWorker.class) .setConstraints(constraints) .build();如果指定了多个约束,您的任务将仅在满足所有约束时才会运行。
如果在任务运行期间某个约束不再得到满足,则 WorkManager 将停止工作器。当约束继续得到满足时,系统将重新尝试执行该任务。
这个挺有用的,不需要写一堆状态监听加判断了
看约束支持
- setRequiredNetworkType
- setRequiresBatteryNotLow
- setRequiresCharging
- setRequiresDeviceIdle
- setRequiresStorageNotLow
- setTriggerContentMaxDelay
- setTriggerContentUpdateDelay
初始延迟
如果您的工作没有约束,或者工作加入队列时所有约束均已得到满足,则系统可能会选择立即运行任务。如果您不希望任务立即运行,则可以将工作指定为在经过一段最短初始延迟时间后再启动。
下面的示例展示了如何将任务设置为在加入队列后至少经过 10 分钟再运行。
OneTimeWorkRequest uploadWorkRequest = new OneTimeWorkRequest.Builder(UploadWorker.class) .setInitialDelay(10, TimeUnit.MINUTES) .build();
注意:执行工作器的确切时间还取决于 WorkRequest 中使用的约束和系统优化方式。WorkManager 经过设计,能够在满足这些约束的情况下提供可能的最佳行为。
重试和退避政策
如果您需要让 WorkManager 重新尝试执行您的任务,可以从工作器返回 Result.retry()
。
然后,系统会根据默认的退避延迟时间和政策重新调度您的工作。退避延迟时间指定了重试工作前的最短等待时间。退避政策定义了在后续重试过程中,退避延迟时间随时间以怎样的方式增长;默认情况下按 EXPONENTIAL
延长。
以下是自定义退避延迟时间和政策的示例。
OneTimeWorkRequest uploadWorkRequest = new OneTimeWorkRequest.Builder(UploadWorker.class) .setBackoffCriteria( BackoffPolicy.LINEAR, OneTimeWorkRequest.MIN_BACKOFF_MILLIS, TimeUnit.MILLISECONDS) .build();
定义任务的输入/输出
您的任务可能需要数据以输入参数的形式传入,或者将数据返回为结果。例如,某个任务负责处理图像上传,它要求以要上传的图像的 URI 为输入,并且可能要求用已上传图像的网址作为输出。
输入和输出值以键值对的形式存储在 Data
对象中。下面的代码展示了如何在 WorkRequest
中设置输入数据。
Data imageData = new Data.Builder() .putString(Constants.KEY_IMAGE_URI, imageUriString) .build(); OneTimeWorkRequest uploadWorkRequest = new OneTimeWorkRequest.Builder(UploadWorker.class) .setInputData(imageData) .build();
Worker
类可通过调用 Worker.getInputData() 访问输入参数。
类似地,Data
类可用于输出返回值。如需返回 Data
对象,请将它添加到 Result.success()
或 Result.failure()
时的 Result
中,如下所示。
public class UploadWorker extends Worker { public UploadWorker( @NonNull Context context, @NonNull WorkerParameters params) { super(context, params); } @Override public Result doWork() { // Get the input String imageUriInput = getInputData().getString(Constants.KEY_IMAGE_URI); // TODO: validate inputs. // Do the work Response response = uploadFile(imageUriInput); // Create the output of the work Data outputData = new Data.Builder .putString(Constants.KEY_IMAGE_URL, response.imageUrl) .build(); // Return the output return Result.success(outputData); } }
注意:按照设计,Data
对象应该很小,值可以是字符串、基元类型或数组变体。如果需要将更多数据传入和传出工作器,应该将数据放在其他位置,例如 Room 数据库。Data 对象的大小上限为 10KB。
标记工作
您可以通过为任意 WorkRequest
对象分配标记字符串,按逻辑对任务进行分组。这样您就可以对使用特定标记的所有任务执行操作。
例如,WorkManager.cancelAllWorkByTag(String)
会取消使用特定标记的所有任务,而 WorkManager.getWorkInfosByTagLiveData(String)
会返回 LiveData
和具有该标记的所有任务的状态列表。
以下代码展示了如何使用 WorkRequest.Builder.addTag(String)
向任务添加“cleanup”标记:
OneTimeWorkRequest cacheCleanupTask =
new OneTimeWorkRequest.Builder(CacheCleanupWorker.class)
.setConstraints(constraints)
.addTag("cleanup")
.build();
总结
WorkManager主要用于不是即时的对稳定性和执行条件有要求的异步任务中,在系统和应用重启后也可得到执行。
使用方法主要是定义任务,添加约束和进行任务队列添加。
上一篇: (两百六十)学习进程和线程概览
下一篇: 常用sql查询语句