WorkManager 简化了复杂任务请求的设置和调度。您可以在以下情景中使用这些 API:
链接任务
您的应用可能需要按特定顺序运行多个任务。您可以通过 WorkManager
创建工作序列并对序列中的任务进行排队。该工作序列将指定多个任务以及这些任务的运行顺序。
例如,假设您的应用有三个 OneTimeWorkRequest
对象:workA
、workB
和 workC
。这些任务必须按该顺序运行。如需对这些任务进行排队,请使用 WorkManager.beginWith(OneTimeWorkRequest)
方法创建一个序列,并传递第一个 OneTimeWorkRequest
对象;该方法会返回一个 WorkContinuation
对象,以定义一个任务序列。然后,使用 WorkContinuation.then(OneTimeWorkRequest)
依次添加剩余的 OneTimeWorkRequest
对象;最后,使用 WorkContinuation.enqueue()
对整个序列进行排队:
Kotlin
WorkManager.getInstance(myContext) .beginWith(workA) // Note: WorkManager.beginWith() returns a // WorkContinuation object; the following calls are // to WorkContinuation methods .then(workB) // FYI, then() returns a new WorkContinuation instance .then(workC) .enqueue()
Java
WorkManager.getInstance(myContext) .beginWith(workA) // Note: WorkManager.beginWith() returns a // WorkContinuation object; the following calls are // to WorkContinuation methods .then(workB) // FYI, then() returns a new WorkContinuation instance .then(workC) .enqueue();
WorkManager
会根据每个任务的指定约束,按请求的顺序运行任务。如果有任务返回 Result.failure()
,整个序列结束。
您还可以将多个 OneTimeWorkRequest
对象传递给任何 beginWith(List<OneTimeWorkRequest>)
和 then(List<OneTimeWorkRequest>)
调用。如果您向单个方法调用传递多个 OneTimeWorkRequest
对象,WorkManager
会并行运行所有这些任务,然后再运行序列中的其他任务。例如:
Kotlin
WorkManager.getInstance(myContext) // First, run all the A tasks (in parallel): .beginWith(Arrays.asList(workA1, workA2, workA3)) // ...when all A tasks are finished, run the single B task: .then(workB) // ...then run the C tasks (in parallel): .then(Arrays.asList(workC1, workC2)) .enqueue()
Java
WorkManager.getInstance(myContext) // First, run all the A tasks (in parallel): .beginWith(Arrays.asList(workA1, workA2, workA3)) // ...when all A tasks are finished, run the single B task: .then(workB) // ...then run the C tasks (in parallel): .then(Arrays.asList(workC1, workC2)) .enqueue();
您可以使用 WorkContinuation.combine(List<OneTimeWorkRequest>)
方法联接多个任务链来创建更为复杂的序列。例如,假设您要运行像这样的序列:
WorkContinuation
设置复杂的链接任务。如需设置该序列,请创建两个单独的链,然后将它们联接成第三个链:
Kotlin
val chain1 = WorkManager.getInstance(myContext) .beginWith(workA) .then(workB) val chain2 = WorkManager.getInstance(myContext) .beginWith(workC) .then(workD) val chain3 = WorkContinuation .combine(Arrays.asList(chain1, chain2)) .then(workE) chain3.enqueue()
Java
WorkContinuation chain1 = WorkManager.getInstance(myContext) .beginWith(workA) .then(workB); WorkContinuation chain2 = WorkManager.getInstance(myContext) .beginWith(workC) .then(workD); WorkContinuation chain3 = WorkContinuation .combine(Arrays.asList(chain1, chain2)) .then(workE); chain3.enqueue();
在这种情况下,WorkManager
会在 workB
之前运行 workA
。它还会在 workD
之前运行 workC
。在 workB
和 workD
都完成后,WorkManager
会运行 workE
。
WorkContinuation
方法有多种变体,可在特定情况下提供简写形式。如需了解详情,请参阅 WorkContinuation
参考文档。
唯一工作序列
您可以创建唯一工作序列,方法是通过调用 beginUniqueWork(String, ExistingWorkPolicy, OneTimeWorkRequest)
(而非 beginWith(OneTimeWorkRequest)
)开始创建序列。每个唯一工作序列都有一个名称,WorkManager
不允许同时存在多个具有相同名称的工作序列。当您创建新的唯一工作序列时,如果已存在同名的未完成序列,您需要指定 WorkManager
应执行什么操作:
当您有不能够多次排队的任务时,唯一工作序列将非常有用。例如,如果您的应用需要将其数据同步到网络,您可能需要对一个名为“sync”的序列进行排队,并指定当已经存在具有该名称的序列时,应该忽略新的任务。当您需要逐步构建一个长任务链时,也可以利用唯一工作序列。例如,照片编辑应用可能允许用户撤消一长串操作。其中的每一项撤消操作可能都需要一些时间来完成,但必须按正确的顺序执行。在这种情况下,应用可以创建一个“撤消”链,并根据需要将每个撤消操作附加到该链上。
输入参数和返回值
为了提高灵活性,您可以将参数传递给任务并让任务返回结果。传递和返回的值是键值对。如需向任务传递参数,请先调用 WorkRequest.Builder.setInputData(Data)
方法,然后再创建 WorkRequest
对象。该方法将接受您使用 Data.Builder
创建的 Data
对象。Worker
类可以通过调用 Worker.getInputData()
来访问这些参数。如需输出返回值,任务应当将其包含在 Result
中,例如返回 Result.success(Data)
。您可以通过观察任务的 WorkInfo
获得输出内容。
例如,假设您有一个 Worker
类,该类会执行一项耗时的计算。以下代码展示了该 Worker
类的内容:
Kotlin
// Define the parameter keys: const val KEY_X_ARG = "X" const val KEY_Y_ARG = "Y" const val KEY_Z_ARG = "Z" // ...and the result key: const val KEY_RESULT = "result" // Define the Worker class: class MathWorker(context : Context, params : WorkerParameters) : Worker(context, params) { override fun doWork(): Result { val x = inputData.getInt(KEY_X_ARG, 0) val y = inputData.getInt(KEY_Y_ARG, 0) val z = inputData.getInt(KEY_Z_ARG, 0) // ...do the math... val result = myLongCalculation(x, y, z); //...set the output, and we're done! val output: Data = workDataOf(KEY_RESULT to result) return Result.success(output) } }
Java
// Define the Worker class: public class MathWorker extends Worker { // Define the parameter keys: public static final String KEY_X_ARG = "X"; public static final String KEY_Y_ARG = "Y"; public static final String KEY_Z_ARG = "Z"; // ...and the result key: public static final String KEY_RESULT = "result"; public MathWorker( @NonNull Context context, @NonNull WorkerParameters params) { super(context, params); } @Override public Result doWork() { // Fetch the arguments (and specify default values): int x = getInputData().getInt(KEY_X_ARG, 0); int y = getInputData().getInt(KEY_Y_ARG, 0); int z = getInputData().getInt(KEY_Z_ARG, 0); // ...do the math... int result = myLongCalculation(x, y, z); //...set the output, and we're done! Data output = new Data.Builder() .putInt(KEY_RESULT, result) .build(); return Result.success(output); } }
要创建工作并传递参数,您可以使用类似以下的代码:
Kotlin
val myData: Data = workDataOf("KEY_X_ARG" to 42, "KEY_Y_ARG" to 421, "KEY_Z_ARG" to 8675309) // ...then create and enqueue a OneTimeWorkRequest that uses those arguments val mathWork = OneTimeWorkRequestBuilder<MathWorker>() .setInputData(myData) .build() WorkManager.getInstance(myContext).enqueue(mathWork)
Java
// Create the Data object: Data myData = new Data.Builder() // We need to pass three integers: X, Y, and Z .putInt(KEY_X_ARG, 42) .putInt(KEY_Y_ARG, 421) .putInt(KEY_Z_ARG, 8675309) // ... and build the actual Data object: .build(); // ...then create and enqueue a OneTimeWorkRequest that uses those arguments OneTimeWorkRequest mathWork = new OneTimeWorkRequest.Builder(MathWorker.class) .setInputData(myData) .build(); WorkManager.getInstance(myContext).enqueue(mathWork);
任务的 WorkInfo
中会提供返回值:
Kotlin
WorkManager.getInstance(myContext).getWorkInfoByIdLiveData(mathWork.id) .observe(this, Observer { info -> if (info != null && info.state.isFinished) { val myResult = info.outputData.getInt(KEY_RESULT, myDefaultValue) // ... do something with the result ... } })
Java
WorkManager.getInstance(myContext).getWorkInfoByIdLiveData(mathWork.getId()) .observe(lifecycleOwner, info -> { if (info != null && info.getState().isFinished()) { int myResult = info.getOutputData().getInt(KEY_RESULT, myDefaultValue)); // ... do something with the result ... } });
如果您链接多个任务,一个任务的输出可以作为任务链中下一个任务的输入。如果是简单链(即一个 OneTimeWorkRequest
后面跟着另一个 OneTimeWorkRequest
),第一个任务通过调用 Result.success(Data)
返回其结果,下一个任务通过调用 getInputData()
提取该结果。如果是更复杂的链(例如有多个任务都将输出发送给同一个后续任务),您可以在 OneTimeWorkRequest.Builder
上定义 InputMerger
,以指定当多个不同任务返回具有相同键的输出时应执行什么操作。
其他资源
如需详细了解 WorkManager,请参阅下面列出的其他资源。
示例
- WorkManager 示例应用
- Sunflower,这是一款园艺应用,展示了使用 Android Jetpack 进行 Android 开发的最佳做法。