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
实例时,父工作请求的输出将作为输入传递给子工作请求。因此,在上面的示例中,plantName1
、plantName2
和 plantName3
的输出将作为输入传递给 cache
请求。
为了管理来自多个父工作请求的输入,WorkManager 使用 InputMerger
。
WorkManager 提供了两种不同类型的 InputMerger
OverwritingInputMerger
尝试将所有输入的所有键添加到输出。如果发生冲突,它将覆盖之前设置的键。ArrayCreatingInputMerger
尝试合并输入,必要时创建数组。
如果您有更具体的用例,那么可以通过子类化 InputMerger
来编写自己的合并器。
OverwritingInputMerger
OverwritingInputMerger
是默认的合并方法。如果合并中存在键冲突,那么键的最新值将覆盖结果输出数据中的任何先前版本。
例如,如果植物输入都具有与它们各自的变量名称匹配的键("plantName1"
、"plantName2"
和 "plantName3"
),那么传递到 cache
工作器的将具有三个键值对。
如果存在冲突,那么最后一个完成的 Worker 将“获胜”,其值将传递到 cache
。
由于您的工作请求是并行运行的,因此您无法保证运行顺序。在上面的示例中,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
将每个键与一个数组配对。如果每个键都是唯一的,那么你的结果就是一系列单元素数组。
如果存在任何键冲突,则任何相应的 value 将被分组到一个数组中。
链和工作状态
只要其工作成功完成(即,返回 Result.success()
),OneTimeWorkRequest
的链就会顺序执行。工作请求可能在运行时失败或被取消,这会对依赖的工作请求产生下游影响。
当第一个 OneTimeWorkRequest
被加入到工作请求链中时,所有后续工作请求都将被阻塞,直到该第一个工作请求的工作完成。
一旦加入队列并且所有工作约束都满足,第一个工作请求就开始运行。如果根 OneTimeWorkRequest
或 List<OneTimeWorkRequest>
中的工作成功完成(即,它返回 Result.success()
),那么下一组依赖的工作请求将被加入队列。
只要每个工作请求都成功完成,这种模式就会传播到工作请求链的其余部分,直到链中的所有工作都完成。虽然这是最简单且通常是首选的情况,但错误状态也同样重要。
当 worker 在处理你的工作请求时发生错误时,你可以根据你定义的 回退策略 重试该请求。重试作为链的一部分的请求意味着,只有该请求将使用提供给它的输入数据重试。任何并行运行的工作都不会受到影响。
有关定义自定义重试策略的更多信息,请参阅 重试和回退策略。
如果该重试策略未定义或已用尽,或者你以其他方式达到 OneTimeWorkRequest
返回 Result.failure()
的某种状态,那么该工作请求及其所有依赖的工作请求将被标记为 FAILED
。
当 OneTimeWorkRequest
被取消时,也适用相同的逻辑。所有依赖的工作请求也被标记为 CANCELLED
,并且它们的工作将不会执行。
请注意,如果你要向一个失败或取消了工作请求的链添加更多工作请求,那么你新添加的工作请求也将被分别标记为 FAILED
或 CANCELLED
。如果你想扩展现有链的工作,请参阅 ExistingWorkPolicy 中的 APPEND_OR_REPLACE
。
在创建工作请求链时,依赖的工作请求应定义重试策略,以确保工作始终能够及时完成。失败的工作请求可能会导致链不完整或状态意外。
有关更多信息,请参阅 取消和停止工作。