Android NDK开发详解后台任务之创建工作链
您可以使用 WorkManager 创建工作链并将其加入队列。工作链用于指定多个依存任务并定义这些任务的运行顺序。当您需要以特定顺序运行多个任务时,此功能尤其有用。
如需创建工作链,您可以使用 WorkManager.beginWith(OneTimeWorkRequest) 或 WorkManager.beginWith(List),这会返回 WorkContinuation 实例。
然后,可以使用 WorkContinuation 通过 then(OneTimeWorkRequest) 或 then(List) 添加 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 实例时,父级工作请求的输出将作为子级的输入传入。因此,在上面的示例中,plantName1、plantName2 和 plantName3 的输出将作为 cache 请求的输入传入。
为了管理来自多个父级工作请求的输入,WorkManager 使用 InputMerger。
WorkManager 提供两种不同类型的 InputMerger:
OverwritingInputMerger 会尝试将所有输入中的所有键添加到输出中。如果发生冲突,它会覆盖先前设置的键。
ArrayCreatingInputMerger 会尝试合并输入,并在必要时创建数组。
如果您有更具体的用例,则可以创建 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 被加入工作请求链队列时,所有后续工作请求会被屏蔽,直到第一个工作请求的工作完成为止。
此图显示一个作业链。第一个作业已加入队列;所有后续的作业都会被屏蔽,直到第一个作业完成为止。
在加入队列且满足所有工作约束后,第一个工作请求开始运行。如果工作在根 OneTimeWorkRequest 或 List 中成功完成(即返回 Result.success()),系统会将下一组依存工作请求加入队列。
此图显示一个作业链。第一个作业已成功完成,其两个直接后继作业已加入队列。剩余作业会被屏蔽,直到其之前的作业完成为止。
只要每个工作请求都成功完成,工作请求链中的剩余工作请求就会遵循相同的运行模式,直到链中的所有工作都完成为止。这是最简单的用例,通常也是首选用例,但处理错误状态同样重要。
如果在工作器处理工作请求时出现错误,您可以根据您定义的退避政策来重试该请求。重试请求链中的某个请求意味着,系统将使用提供给该请求的输入数据仅对该请求进行重试。并行运行的所有其他作业均不会受到影响。
此图显示一个作业链。其中一个作业失败,但已定义退避政策。该作业将在一段适当的时间过后重新运行,链中跟随其后的作业会被屏蔽,直到该作业成功运行为止。
如需详细了解如何定义自定义重试策略,请参阅重试和退避政策。
如果该重试政策未定义或已用尽,或者您以其他方式已达到 OneTimeWorkRequest 返回 Result.failure() 的某种状态,该工作请求和所有依存工作请求都会被标记为 FAILED.
此图显示一个作业链。一个作业失败,无法重试。因此,链中在该作业后面的所有作业也都将失败。
OneTimeWorkRequest 被取消时遵循相同的逻辑。任何依存工作请求也会被标记为 CANCELLED,并且无法执行其工作。
此图显示一个作业链。一个作业已被取消。因此,链中在该作业后面的所有作业也都会被取消。
请注意,如果要向已失败或已取消工作请求的链附加更多工作请求,新附加的工作请求也会分别标记为 FAILED 或 CANCELLED。如果您想扩展现有链的工作,请参阅 ExistingWorkPolicy 中的 APPEND_OR_REPLACE。
创建工作请求链时,依存工作请求应定义重试政策,以确保始终及时完成工作。失败的工作请求可能会导致链不完整和/或出现意外状态。
如需了解详情,请参阅取消和停止工作。