链接工作

WorkManager 允许您创建和排队一个工作链,该工作链指定多个依赖任务并定义它们的运行顺序。当您需要按特定顺序运行多个任务时,此功能非常有用。

要创建一个工作链,您可以使用 WorkManager.beginWith(OneTimeWorkRequest)WorkManager.beginWith(List<OneTimeWorkRequest>) ,它们都返回 WorkContinuation 的实例。

然后可以使用 WorkContinuation 使用 then(OneTimeWorkRequest)then(List<OneTimeWorkRequest>) 添加依赖的 OneTimeWorkRequest 实例。

每次调用 WorkContinuation.then(...) 都返回一个新的 WorkContinuation 实例。如果添加了 OneTimeWorkRequest 实例的 List ,这些请求可能会并行运行。

最后,您可以使用 WorkContinuation.enqueue() 方法来 enqueue() 您的 WorkContinuation 链。

让我们看一个示例。在此示例中,配置了 3 个不同的 Worker 作业以运行(可能并行)。然后将这些 Worker 的结果合并并传递到缓存 Worker 作业。最后,将该作业的输出传递到上传 Worker,该 Worker 将结果上传到远程服务器。

Kotlin

WorkManager.getInstance(myContext)
   // Candidates to run in parallel
   .beginWith(listOf(plantName1, plantName2, plantName3))
   // Dependent work (only runs after all previous work in chain)
   .then(cache)
   .then(upload)
   // Call enqueue to kick things off
   .enqueue()

Java

WorkManager.getInstance(myContext)
   // Candidates to run in parallel
   .beginWith(Arrays.asList(plantName1, plantName2, plantName3))
   // Dependent work (only runs after all previous work in chain)
   .then(cache)
   .then(upload)
   // Call enqueue to kick things off
   .enqueue();

输入合并器

当您链接 OneTimeWorkRequest 实例时,父工作请求的输出将作为输入传递给子工作请求。因此,在上面的示例中,plantName1plantName2plantName3 的输出将作为输入传递给 cache 请求。

为了管理来自多个父工作请求的输入,WorkManager 使用 InputMerger

WorkManager 提供了两种不同类型的 InputMerger

如果您有更具体的用例,那么可以通过子类化 InputMerger 来编写自己的合并器。

OverwritingInputMerger

OverwritingInputMerger 是默认的合并方法。如果合并中存在键冲突,那么键的最新值将覆盖结果输出数据中的任何先前版本。

例如,如果植物输入都具有与它们各自的变量名称匹配的键("plantName1""plantName2""plantName3"),那么传递到 cache 工作器的将具有三个键值对。

Diagram showing three jobs passing different outputs to the next job in the chain. Since the three outputs all have different keys, the next job receives three key/value pairs.

如果存在冲突,那么最后一个完成的 Worker 将“获胜”,其值将传递到 cache

Diagram showing three jobs passing outputs to the next job in the chain. In this case, two of those jobs produce outputs with the same key. As a result, the next job receives two key/value pairs, with one of the conflicting outputs dropped.

由于您的工作请求是并行运行的,因此您无法保证运行顺序。在上面的示例中,plantName1 的值可能为 "tulip""elm" ,具体取决于最后写入的值。如果您有键冲突的可能性,并且需要在合并中保留所有输出数据,那么 ArrayCreatingInputMerger 可能是一个更好的选择。

ArrayCreatingInputMerger

对于上面的示例,假设我们想要保留所有工厂名称 Worker 的输出,则应使用 ArrayCreatingInputMerger

Kotlin

val cache: OneTimeWorkRequest = OneTimeWorkRequestBuilder<PlantWorker>()
   .setInputMerger(ArrayCreatingInputMerger::class)
   .setConstraints(constraints)
   .build()

Java

OneTimeWorkRequest cache = new OneTimeWorkRequest.Builder(PlantWorker.class)
       .setInputMerger(ArrayCreatingInputMerger.class)
       .setConstraints(constraints)
       .build();

ArrayCreatingInputMerger 将每个键与一个数组配对。如果每个键都是唯一的,那么你的结果就是一系列单元素数组。

Diagram showing three jobs passing different outputs to the next job in the chain. The next job is passed three arrays, one for each of the output keys. Each array has a single member.

如果存在任何键冲突,则任何相应的 value 将被分组到一个数组中。

Diagram showing three jobs passing outputs to the next job in the chain. In this case, two of those jobs produce outputs with the same key. The next job is passed two arrays, one for each key. One of those arrays has two members, since there were two outputs with that key.

链和工作状态

只要其工作成功完成(即,返回 Result.success()),OneTimeWorkRequest 的链就会顺序执行。工作请求可能在运行时失败或被取消,这会对依赖的工作请求产生下游影响。

当第一个 OneTimeWorkRequest 被加入到工作请求链中时,所有后续工作请求都将被阻塞,直到该第一个工作请求的工作完成。

Diagram showing a chain of jobs. The first job is enqueued; all successive jobs are blocked until the first one finishes.

一旦加入队列并且所有工作约束都满足,第一个工作请求就开始运行。如果根 OneTimeWorkRequestList<OneTimeWorkRequest> 中的工作成功完成(即,它返回 Result.success()),那么下一组依赖的工作请求将被加入队列。

Diagram showing a chain of jobs. The first job has succeeded, and its two immediate successors are enqueued. The remaining jobs are blocked their preceding jobs finish.

只要每个工作请求都成功完成,这种模式就会传播到工作请求链的其余部分,直到链中的所有工作都完成。虽然这是最简单且通常是首选的情况,但错误状态也同样重要。

当 worker 在处理你的工作请求时发生错误时,你可以根据你定义的 回退策略 重试该请求。重试作为链的一部分的请求意味着,只有该请求将使用提供给它的输入数据重试。任何并行运行的工作都不会受到影响。

Diagram showing a chain of jobs. One of the jobs failed, but had a backoff policy defined. That job will rerun after the appropriate amount of time has passed. The jobs after it in the chain are blocked until it runs successfully.

有关定义自定义重试策略的更多信息,请参阅 重试和回退策略

如果该重试策略未定义或已用尽,或者你以其他方式达到 OneTimeWorkRequest 返回 Result.failure() 的某种状态,那么该工作请求及其所有依赖的工作请求将被标记为 FAILED

Diagram showing a chain of jobs. One job has failed and cannot be retried. As a result, all jobs after it in the chain also fail.

OneTimeWorkRequest 被取消时,也适用相同的逻辑。所有依赖的工作请求也被标记为 CANCELLED,并且它们的工作将不会执行。

Diagram showing a chain of jobs. One job has been cancelled. As a result, all jobs after it in the chain are also cancelled.

请注意,如果你要向一个失败或取消了工作请求的链添加更多工作请求,那么你新添加的工作请求也将被分别标记为 FAILEDCANCELLED。如果你想扩展现有链的工作,请参阅 ExistingWorkPolicy 中的 APPEND_OR_REPLACE

在创建工作请求链时,依赖的工作请求应定义重试策略,以确保工作始终能够及时完成。失败的工作请求可能会导致链不完整或状态意外。

有关更多信息,请参阅 取消和停止工作