WorkManager 基础知识

原文链接:WorkManager basics | Android Developers

使用 WorkManager,您可以轻易设定一个任务并将其传递给系统来在您指定的情况下执行。

本小节的话题包括了最基础的 WorkManager 特性。您将学会如何设定一个任务、指定其执行的条件以及交由系统处理。您还将学会如何设定重复任务。

欲了解更多关于 WorkManager 的进阶知识,例如链式任务、传递并返回值等等,请参阅 WorkManager 高级进阶。欲了解全部细节,请参阅 WorkManager 参考文档

注意:欲将 WorkManager 库导入您的 Android 项目,请参阅为您的项目添加 Android 架构组件

类和概念

WorkManager 的 API 使用了几个不同的类。在一些情况下,您需要继承其中之一。

如下是最重要的 WorkManager 类:

典型流程

假设您正在编写一个相册应用,而且该相册需要定期地压缩其存储的图像。您想要使用 WorkManager 的 API 来安排图像压缩的任务。在这个情境中,您不太在乎压缩发生的具体时间,而是只想设定这些任务后就撒手不管。

首先,您需要定义您的 Worker 类,并覆写其 doWork()) 方法。您的 Worker 类指定了执行操作的具体细节,但并不包含任何关于任务应当执行的信息。

  1. public class CompressWorker extends Worker {
  2. public CompressWorker(
  3. @NonNull Context context,
  4. @NonNull WorkerParameters params) {
  5. super(context, params);
  6. }
  7. @Override
  8. public Worker.Result doWork() {
  9. // 在这里完成工作——就这个例子而言是压缩存储的图像。
  10. // 本示例中并没有传递参数,因而该任务假设为“压缩整个图像库”。
  11. myCompress();
  12. // 根据您的返回值来标明任务是成功还是失败:
  13. return Result.success();
  14. // (返回 Result.retry() 会让 WorkManager 过会儿重试该任务;
  15. // 返回 Result.failure() 则是说明不需要重试。)
  16. }
  17. }

接下来,您根据这个 Worker 来创建一个 OneTimeWorkRequest,并使用 WorkManager 来将其加入队列:

  1. OneTimeWorkRequest compressionWork =
  2. new OneTimeWorkRequest.Builder(CompressWorker.class)
  3. .build();
  4. WorkManager.getInstance().enqueue(compressionWork);

WorkManager 会选择合适的时间来运行这个任务,平衡考虑各种因素,比如:系统负载、设备是否连接电源,等等。在大多数情况下,如果您不指定任何限制条件,WorkManager 就会立即执行您的任务。如果您需要检查任务状态,只需通过相应的 LiveData[`WorkInfo`](https://developer.android.google.cn/reference/androidx/work/WorkInfo.html) 的句柄来获得其 WorkInfo 对象。例如,如果您想要检查一个任务是否已经完成,您就可以这样编写代码:

  1. WorkManager.getInstance().getWorkInfoByIdLiveData(compressionWork.getId())
  2. .observe(lifecycleOwner, workInfo -> {
  3. // 利用任务状态来做些事
  4. if (workInfo != null && workInfo.getState().isFinished()) {
  5. // ...
  6. }
  7. });

欲了解更多有关使用 LiveData 的信息,请参阅 LiveData 概览

任务限制条件(Constraints)

只要您愿意,您就能指定任务运行时的限制条件。例如,您可能想要指定某个任务只在设备连接到电源并处于空闲状态时执行。在这种情况下,您需要创建一个 OneTimeWorkRequest.Builder 对象,并使用该 builder 来创建真正的 OneTimeWorkRequest 对象。

  1. // 创建一个 Constraints 对象来定义任务运行时的限制条件
  2. Constraints myConstraints = new Constraints.Builder()
  3. .setRequiresDeviceIdle(true)
  4. .setRequiresCharging(true)
  5. // 还有很多其他 constraints 可以用,
  6. // 请查看 Constraints.Builder 参考文档
  7. .build();
  8. // ……然后创建一个 OneTimeWorkRequest 来使用上述限制条件
  9. OneTimeWorkRequest compressionWork =
  10. new OneTimeWorkRequest.Builder(CompressWorker.class)
  11. .setConstraints(myConstraints)
  12. .build();

之后,仍旧是将新创建的 OneTimeWorkRequest 对象传入 WorkManager.enqueue())。WorkManager 会在考虑到这些限制条件的情况下寻找时机来执行任务。

取消一个任务

您可以在把一个任务加入队列后将其取消。欲取消一个任务,您需要从 WorkRequest 对象中获得其 ID。例如,如下的代码取消了上面提到的 compressionWork

  1. UUID compressionWorkId = compressionWork.getId();
  2. WorkManager.getInstance().cancelWorkById(compressionWorkId);

WorkManager 会尽其所能地取消任务,但这从本质上来说还是不确定的——在您试图取消该任务时,它可能已经在执行或完成了。WorkManager 还提供了取消一个 唯一任务序列 当中、或有特定 标签(Tag)的全部任务的方法——当然,这仍只是尽力而为。

加注标签(Tag)的任务

您可以通过为任意 WorkRequest 指定标签字符串的方式,来将您的任务按逻辑关系分组。欲设置一个标签,请按下例所示调用 WorkRequest.Builder.addTag()

  1. OneTimeWorkRequest cacheCleanupTask =
  2. new OneTimeWorkRequest.Builder(MyCacheCleanupWorker.class)
  3. .setConstraints(myConstraints)
  4. .addTag("清理")
  5. .build();

WorkManager 提供了若干实用方法来让您操作特定标签下的所有任务。例如:WorkManager.cancelAllWorkByTag(String)) 能取消加注了特定标签的所有任务,而 WorkManager.getWorkInfosByTagLiveData(String)) 能把加注了特定标签的所有任务的 WorkInfo 作为一个列表返回。

重复(Recurring)任务

您可能有个任务需要重复执行,例如:图片管理器应用可能不会只把其照片压缩仅仅一次——更可能的是,它会时不时检查自己的分享照片,来判断是否有新加入的或变更的图像需要被压缩。这种重复任务可以压缩新找到的图片,换言之,它能在新找到需要压缩的图片时,触发一个新的“压缩这张图片”的任务。

欲创建一个重复任务,请使用 PeriodicWorkRequest.Builder 类来创建一个 PeriodicWorkRequest 对象,并像 OneTimeWorkRequest 那样将其加入队列。例如,假设我们定义了一个 PhotoCheckWorker 类来辨别需要压缩的图像,如果您想要每隔12小时执行一次清点任务,您需要如下例所示地创建一个 PeriodicWorkRequest 对象:

  1. PeriodicWorkRequest.Builder photoCheckBuilder =
  2. new PeriodicWorkRequest.Builder(PhotoCheckWorker.class, 12,
  3. TimeUnit.HOURS);
  4. // ……您愿意的话,也可在此 builder 中设定限制条件……
  5. // 创建实际的任务对象:
  6. PeriodicWorkRequest photoCheckWork = photoCheckBuilder.build();
  7. // 并将此重复任务入队
  8. WorkManager.getInstance().enqueue(photoCheckWork);

WorkManager 会尝试按您请求的时间间隔运行您的任务,具体取决于您施加的限制条件及其他要求。