链接工作

您可以使用 WorkManager 创建工作链并将其加入队列。工作链用于指定多个依存任务并定义这些任务的运行顺序。当您需要以特定顺序运行多个任务时,此功能尤其有用。

如需创建工作链,您可以使用 WorkManager.beginWith(OneTimeWorkRequest)WorkManager.beginWith(List<OneTimeWorkRequest>),这会返回 WorkContinuation 实例。

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

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

最后,您可以使用 WorkContinuation.enqueue() 方法对 WorkContinuation 工作链执行 enqueue() 操作。

下面我们来看一个示例。在本例中,有 3 个不同的工作器作业配置为运行(可能并行运行)。然后这些工作器的结果将联接起来,并传递给正在缓存的工作器作业。最后,该作业的输出将传递到上传工作器,由上传工作器将结果上传到远程服务器。

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 工作器的数据将具有三个键值对。

此图显示了三个作业将不同的输出传递给链中的下一个作业。由于这三个输出都具有不同的键,因此下一个作业将收到三个键值对。

如果存在冲突,那么最后一个工作器将在争用中“取胜”,其值将传递给 cache

此图显示了三个作业将输出传递给链中的下一个作业。在本例中,其中有两个作业使用同一个键生成输出。因此,下一个作业将收到两个键值对,其中一个存在冲突的输出会被丢弃。

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

ArrayCreatingInputMerger

对于上面的示例,假设我们要保留所有植物名称工作器的输出,则应使用 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 将每个键与数组配对。如果每个键都是唯一的,您会得到一系列一元数组。

此图显示了三个作业将不同的输出传递给链中的下一个作业。有三个数组传递到下一个作业,每个输出键对应一个数组。每个数组都有一个成员。

如果存在任何键冲突,那么所有对应的值会分组到一个数组中。

此图显示了三个作业将输出传递给链中的下一个作业。在本例中,其中有两个作业使用同一个键生成输出。有两个数组传递到下一个作业,每个键对应一个数组。其中一个数组有两个成员,因为有两个输出具有该键。

链接和工作状态

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

当第一个 OneTimeWorkRequest 被加入工作请求链队列时,所有后续工作请求会被屏蔽,直到第一个工作请求的工作完成为止。

此图显示一个作业链。第一个作业已加入队列;所有后续的作业都会被屏蔽,直到第一个作业完成为止。

在加入队列且满足所有工作约束后,第一个工作请求开始运行。如果工作在根 OneTimeWorkRequestList<OneTimeWorkRequest> 中成功完成(即返回 Result.success()),系统会将下一组依存工作请求加入队列。

此图显示一个作业链。第一个作业已成功完成,其两个直接后继作业已加入队列。剩余作业会被屏蔽,直到其之前的作业完成为止。

只要每个工作请求都成功完成,工作请求链中的剩余工作请求就会遵循相同的运行模式,直到链中的所有工作都完成为止。这是最简单的用例,通常也是首选用例,但处理错误状态同样重要。

如果在工作器处理工作请求时出现错误,您可以根据您定义的退避政策来重试该请求。重试请求链中的某个请求意味着,系统将使用提供给该请求的输入数据仅对该请求进行重试。并行运行的所有其他作业均不会受到影响。

此图显示一个作业链。其中一个作业失败,但已定义退避政策。该作业将在一段适当的时间过后重新运行,链中跟随其后的作业会被屏蔽,直到该作业成功运行为止。

如需详细了解如何定义自定义重试策略,请参阅重试和退避政策

如果该重试政策未定义或已用尽,或者您以其他方式已达到 OneTimeWorkRequest 返回 Result.failure() 的某种状态,该工作请求和所有依存工作请求都会被标记为 FAILED.

此图显示一个作业链。一个作业失败,无法重试。因此,链中在该作业后面的所有作业也都将失败。

OneTimeWorkRequest 被取消时遵循相同的逻辑。任何依存工作请求也会被标记为 CANCELLED,并且无法执行其工作。

此图显示一个作业链。一个作业已被取消。因此,链中在该作业后面的所有作业也都会被取消。

请注意,如果要向已失败或已取消工作请求的链附加更多工作请求,新附加的工作请求也会分别标记为 FAILEDCANCELLED。如果您想扩展现有链的工作,请参阅 ExistingWorkPolicy 中的 APPEND_OR_REPLACE

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

如需了解详情,请参阅取消和停止工作