Android Architecture Component WorkManager 高级(翻译)
Android Architecture Component WorkManager 高级(翻译)
原文:https://developer.android.com/topic/libraries/architecture/workmanager/advanced
通过 WorkManager 可以轻松地设置和安排复杂的任务请求。你可以在以下场景使用这些 APIs:
- 通过指定顺序去执行 tasks 的 链序列。
- 唯一的 命名序列,以及在应用启动两个同名序列时发生的情况的规则。
- Tasks 的 输入输出值,包括每个 task 的输出作为参数输入到下一个 tasks 中的链 tasks。
链 tasks
你的 app 可能需要以一个特定的顺序来执行多个 tasks。WorkManager
允许你创建一个工作序列并对它进行排队,该序列指定多个 tasks 以及它应该按什么顺序运行。
举个例子,假设你的 app 有三个 OneTimeWorkRequest
对象:workA
,workB
,workC
。任务必须要按照这个顺序执行。为了排队它们,要通过 WorkManager.beginWith()
) 方法创建一个序列,传入第一个 OneTimeWorkRequest
对象;这个方法返回一个 WorkContinuation
对象,它定义了 tasks 的序列。然后使用 WorkContinuation.then()
按照顺序增加其它的 OneTimeWorkRequest
对象,最后,使用 WorkContinuation.enqueue()
来排队整个序列:
1 | WorkManager.getInstance() |
WorkManager
会按照请求的顺序以及每个 task 指定的约束来运行 tasks。如果 任何 task 返回了 Worker.Result.FAILURE
,则整个序列结束。
你也可以传入多个 OneTimeWorkRequest
对象到 beginWith()
) 和 .then()
调用。如果你传入几个 OneTimeWorkRequest
到一个单独的方法调用,WorkManager
会在运行其余 tasks 之前运行这些 tasks(并行)。比如:
1 | WorkManager.getInstance() |
你可以通过 WorkContinuation.combine()
方法连接多个链来创建更复杂的序列。比如,假设你想要运行像以下的序列:
要设置这个序列,创建两个独立的链,然后把它们链接在一起形成第三个:
1 | val chain1 = WorkManager.getInstance() |
在这种情况下,WorkManager
在 workB
之前运行 workA
。运行 workD
之前运行 workC
。在 workB
和 workD
都完成之后,WorkManager
运行 workE
。
注意:当 WorkManager 按照顺序运行没个子链,不能保证 链1 中的任务与 链2 中的任务可能重叠。比如,workB 可能在 workC 之前或者之后运行,或者同时运行。只能保证每个子链中的 task 将按顺序运行;就是,workB 不会运行直到 workA 完成。
WorkContinuation
有许多变种来提供为特定情况提供快捷。举个例子,WorkContinuation.combine(OneTimeWorkRequest, WorkContinuation…)
) 方法是指示 WorkManager
完成所有指定的 WorkContinuation
链,然后完成指定的 OneTimeWorkRequest
。详请可参阅 WorkContinuation。
唯一工作序列
你可以通过调用 beginUniqueWork()
) 而不是 beginWith()
) 开始一个序列来创建一个 唯一的工作序列。每一个唯一工作序列都有一个名字;WorkManager
一次只允许一个序列具有该名字。当你创建一个新的唯一工作序列时,你要指定如果已经有一个相同名字并且未完成的序列时 WorkManager
应该怎么做:
唯一工作序列在你有一个 task 不该排队多次的时候很有用。举个例子,如果你的 app 需要同步数据到网络,你可能对名为 “sync” 的序列进行排队,然后指定如果已经有这个名字的序列存在,则你新的 task 应该被忽略。唯一工作序列在你需要去逐渐建立一个长长的任务链时也很有用。举个例子,一个图片编辑 app 可能会让用户撤销一个很长的动作链。这些每个撤销的操作都可能会需要花费一些时间,但是它们需要以一个正确的顺序被执行。在这个情况下,app 应该创建一个 “undo” 链,并且如果需要则追加每个撤销操作。
输入和输出值
为了更大的灵活性,你可以传入参数到你的 tasks 并让 task 返回值。输入输出值是键值对。要传入值到一个 task,则需要在你创建 WorkRequest
对象之前调用 WorkRequest.Builder.setInputData()
方法。这个方法接收一个 Data
对象,你可以通过 Data.Builder
来创建它。Worker
类可以通过 Worker.getInputData()
来访问这些参数。要输出一个返回值,task 要调用 Worker.setOutputData()
,它接受一个 Data
对象。你可以通过观察 task 的 LiveData<WorkStatus>
来得到输出。
举个例子,假设你有一个 Worker
类来执行耗时的计算。以下代码展示了 Worker
类应该是怎么样的:
1 | // Define the parameter keys: |
要创建一个 worker 并传入参数,你应该如下编写代码:
1 | val myData: Data = mapOf("KEY_X_ARG" to 42, |
返回值会在 task 的 WorkStatus
中可用:
1 | WorkManager.getInstance().getStatusById(mathWork.id) |
如果你链接了 tasks,一个 task 的输出可作为链中下一个 task 的输入。如果它是一个简单链,使用单个的 OneTimeWorkRequest
链接另一个单个 OneTimeWorkRequest
,第一个 tasker 通过调用 setOutputData()
) 返回结果,然后下一个 task 通过调用 getInputData()
获取结果。如果链更复杂 —— 比如,因为几个 task 都发送输入到一个单个的后续任务 —— 你可以在 OneTimeWorkRequest.Builder
定义一个 InputMerger
来指定如果多个 tasks 返回一个相同 key 的输出时应该怎么处理。
额外的资源
WorkManager
是一个 Android Jetpack architecture component。可参阅使用到它的 Sunflower demo app。
本文链接:https://blog.wangjiegulu.com/2018/10/20/android_architecture_components_workermanager_advanced/
版权声明:本博客所有文章除特别声明外,均采用 CC BY 4.0 CN协议 许可协议。转载请注明出处。