“Rusty brown chains wrap around each other on a locked up gate” by Katherine Chase on Unsplash

Exploring Jetpack: The power of chains in the WorkManager APIs

In this I/O ’18, Google released WorkManager APIs to schedule the work. In the last article, we discussed about how work manager APIs work under and how you can use these APIs to schedule the work to run in particular condition. (If you haven't read the previous article, I highly recommend you to read it before proceeding.)

In this article you are going to learn how to chain multiple works together and run the works in particular order. Let’s start unleashing the power of chains.


Chaining the works:

  • There might be some chance that you want to run some tasks in particular order. Work manager provides chains to order your works in predefined order.
  • For an example, your photo editor app needs to compress the image first and later that image should be uploaded to the server. For this example, you need two tasks — one for compressing an image and other for uploading an image — to be run in sequentially.
  • With the work manager, you can easily chain these tasks to run sequentially or parallelly or in any combinations of that.
  • Remember that if any of the work fail in the chain, the chain won’t run all the works scheduled to run after that failed work.

How to chain works?

  • To chain two or more works, work manager APIs provides two methods: 1) beginWith() and 2) then(). You can pass the WorkRequest of the Worker you want to run.
  • As the name suggests begin with beginWith() method indicates the start point of the chain.
  • After beginWith(), you can add multiple then() calls. The work will run after the previous work is completed.

Chaining works in sequential execution:

  • Let’s take our above example. The work for uploading the photo should be performed after the photo is compressed. So for this example, we need to schedule both the workers to run sequentially — one after another.
  • Here is how we can create anew work request to chain both the task:
WorkManager.getInstance()
.beginWith(compressWork)
.then(uploadWork)// then() returns new WorkContinuation instance
.enqueue();

Understanding data flow in sequential chains:

  • While chaining multiple tasks sequentially, the outputs from one task are available as inputs to the next task in the chain.
  • If it’s a simple chain, with a single OneTimeWorkRequest followed by another single OneTimeWorkRequest, the first task returns its result by calling setOutputData(), and the next task fetches that result by calling getInputData().
  • In above example, the compressWork(A) will run first and it will return the WorkComputation in return when the work is finish. This result of compressWork will then passed to uploadWork(B).

Chaining works in parallel execution:

  • Let’s consider a more complex example. You need to run the works A1, A2 and A3 in parallel, then after you need to run work B and then after you need to run work C1 and C2 in parallel.
  • Here is how you can chain them.
WorkManager.getInstance()
.beginWith(workA1, workA2, workA3)
.then(workB)
.then(workC1, workC2)
.enqueue();

Understanding data flow in parallel chains:

  • In above example work A1, A2 and A3 run in parallel. The work B won’t start executing until all the works running in parallel completes.
  • So, once A1, A2 and A3 complete their work, the combined output of all those works will be passed as an input of work B.
  • Here you can set InputMerger in your OneTimeWorkRequest.Builder to specify what should happen if different tasks return an output with the same key.
  • Now when the work B completes the execution, work C1 and C2 will receive the same data in input from work B.

Combining multiple chains:

  • Work manager library provides an easy way to combine multiple chains to execute in parallel.
  • Let’s consider that you have chain 1, that runs work A1 and work A2 in a sequence. Similarly, chain 2 has work B1 and B2 running sequentially.
  • Now you want to combine those chains such a way that they can run parallel and start executing work C as soon as both the chains complete their execution.
  • Here is how you can use combine() method achieve this.
WorkContinuation chain1 = WorkManager.getInstance()
.beginWith(workA1)
.then(workA2);
WorkContinuation chain2 = WorkManager.getInstance()
.beginWith(workB1)
.then(workB2);
WorkContinuation chain3 = WorkContinuation
.combine(chain1, chain2) //Combines chain 1 and 2
.then(workC);
chain3.enqueue();
Here work manager runs each subchain in a order that there is no guarantee of the order of execution between different subchains. For example, here work A2 might execute before B1.
You can relate combine with the combine operator of Rx.

~If you liked the article, click the 💚 below so more people can see it! Also, you can follow me on Twitter or Medium , so you get updates regarding my upcoming article!!~