Chaining Work

Introduction

WorkManager allows you to create and enqueue a chain of work that specifies multiple dependent tasks, and defines what order they should run in. This is particularly useful when you need to run several tasks in a particular order.

To create a chain of work, you can use WorkManager.beginWith(OneTimeWorkRequest) or WorkManager.beginWith(List<OneTimeWorkRequest>) , which return an instance of WorkContinuation.

A WorkContinuation can then be used to add dependent OneTimeWorkRequests using WorkContinuation.then(OneTimeWorkRequest) or WorkContinuation.then(List<OneTimeWorkRequest>) .

Every invocation of the WorkContinuation.then(...), returns a new instance of WorkContinuation. If you add a List of OneTimeWorkRequests, these requests can potentially run in parallel.

Finally, you can use the WorkContinuation.enqueue() method to enqueue() your chain of WorkContinuations.

Let's look at an example where an application runs image filters on 3 different images (potentially in parallel), then compresses those images together, and then uploads them.

Kotlin

WorkManager.getInstance()
    // Candidates to run in parallel
    .beginWith(listOf(filter1, filter2, filter3))
    // Dependent work (only runs after all previous work in chain)
    .then(compress)
    .then(upload)
    // Don't forget to enqueue()
    .enqueue()

Java

WorkManager.getInstance()
    // Candidates to run in parallel
    .beginWith(Arrays.asList(filter1, filter2, filter3))
    // Dependent work (only runs after all previous work in chain)
    .then(compress)
    .then(upload)
    // Don't forget to enqueue()
    .enqueue();

Input Mergers

When using chains of OneTimeWorkRequests, the output of parent OneTimeWorkRequests are passed in as inputs to the children. So in the above example, the outputs of filter1, filter2 and filter3 would be passed in as inputs to the compress request.

In order to manage inputs from multiple parent OneTimeWorkRequests, WorkManager uses InputMergers.

There are two different types of InputMergers provided by WorkManager:

For the above example, given we want to preserve the outputs from all image filters, we should use an ArrayCreatingInputMerger.

Kotlin

val compress: OneTimeWorkRequest = OneTimeWorkRequestBuilder<CompressWorker>()
    .setInputMerger(ArrayCreatingInputMerger::class)
    .setConstraints(constraints)
    .build()

Java

OneTimeWorkRequest compress =
    new OneTimeWorkRequest.Builder(CompressWorker.class)
        .setInputMerger(ArrayCreatingInputMerger.class)
        .setConstraints(constraints)
        .build();

Chaining and Work Statuses

There are a couple of things to keep in mind when creating chains of OneTimeWorkRequests.

  • Dependent OneTimeWorkRequests are only unblocked (transition to ENQUEUED), when all its parent OneTimeWorkRequests are successful (that is, they return a Result.success()).

  • When any parent OneTimeWorkRequest fails (returns a Result.failure(), then all dependent OneTimeWorkRequests are also marked as FAILED.

  • When any parent OneTimeWorkRequest is cancelled, all dependent OneTimeWorkRequests are also marked as CANCELLED.

For more information, see Cancelling and Stopping Work.