Workout your tasks with WorkManager — Advanced Topics
Tags: androiddev, androidjetpack, workmanager, androidarchitecture
Published: 2020-06-27 13:57:44

---
title: Workout your tasks with WorkManager — Advanced Topics
published: true
date: 2019-09-15 17:09:04 UTC
tags: androiddev,androidjetpack,workmanager,androidarchitecture
canonical_url: https://proandroiddev.com/workout-your-tasks-with-workmanager-advanced-topics-c469581c235b
---

### Workout your tasks with WorkManager — Advanced Topics

_“WorkManager is a library for managing_ **_deferrable_** _and_ **_guaranteed_** _background work.”_

![](https://cdn-images-1.medium.com/max/960/1*yeqx9VaXQkbt-0oDVmItVg.png)

In my previous two posts about [WorkManage](https://developer.android.com/topic/libraries/architecture/workmanager) I covered topics like:

- Android memory model
- Android battery optimizations
- Current background processing solutions
- Where is WorkManager placed in the background work schema
- WorkManager components: Worker, WorkRequest and WorkManager
- Constraints
- Input/Output Data

- [Workout your tasks with WorkManager — Intro](https://dev.to/magdamiu/workout-your-tasks-with-workmanager-intro-pca-temp-slug-2242387)
- [Workout your tasks with WorkManager — Basics](https://dev.to/magdamiu/workout-your-tasks-with-workmanager-basics-466d-temp-slug-82140)

In this blog post I’ll cover some extra features of the WorkManager library like:

- how to identify a task
- how to get the status of a task
- _BackoffPolicy_
- how to combine the tasks and the graphs of tasks (chaining the work)
- how to merge the inputs and outputs
- what are the Threading options in WorkManager

![](https://cdn-images-1.medium.com/max/1024/1*MC2ibFLJ533e0WMH80a5Dg.png)<figcaption>WorkManager mind map diagram</figcaption>

#### 1️⃣ **Identify a task**

After a task (work) was created we will be interested in knowing the status of it, but in order to obtain this objective we should have some mechanisms that could be used to identify the task (work). There are 3 main ways that could be used to identify the work:

1. **Unique id (UUID)**: the id associated to the WorkRequest is generated by the library and it is not developer-friendly
2. **Tag** : a task could contain many tags
3. **Unique name** : a task could have only one unique name

{% gist https://gist.github.com/magdamiu/89d0108d4c39c8533ebe1e201aa072e6 %}

{% gist https://gist.github.com/magdamiu/5bb59f4b57520534f5f697620468d5d0 %}

{% gist https://gist.github.com/magdamiu/698371e4037e09501ae66395d548ab5f %}

{% gist https://gist.github.com/magdamiu/83fc10c76c9b78eadee8d12f4831fcce %}

#### 2️⃣ Get the status of a task

![](https://cdn-images-1.medium.com/max/960/1*fzaPsfAoo1qaog3UHbhLdg.png)<figcaption>WorkInfo contains info about a particular WorkRequest</figcaption>

![](https://cdn-images-1.medium.com/max/960/1*ez5jaaciTzOooHsOX7_-Ug.png)

By having the possibility to identify a task we are able to know more about its status by using LiveData or we also have the possibility to cancel it.

**WorkManager & LiveData = ❤️**

{% gist https://gist.github.com/magdamiu/4d1ea5454cf7f57173255b69efcc45d1 %}

**Cancel a task ** ❌

{% gist https://gist.github.com/magdamiu/4a28bba668a337a8b2505c3de628fcd3 %}

#### **3️⃣ WorkManager Policies**

❗ **Existing Work Policy enums**

- **KEEP ** — keeps the existing unfinished WorkRequest. Enqueues it if one does not already exist.
- **REPLACE ** — always replace the WorkRequest. Cancels and deletes the old one, if it exists.
- **APPEND ** — appends work to an existing chain or create a new chain.

KEEP + REPLACE + APPEND = _ExistingWorkPolicy_

KEEP + REPLACE = _ExistingPeriodicWorkPolicy_

❗ **BackoffPolicy enum**

**EXPONENTIAL —**  Used to indicate that WorkManager should increase the backoff time exponentially

**LINEAR — ** Used to indicate that WorkManager should increase the backoff time linearly

For a **BackoffPolicy** of 15 seconds, will be as next:

- For linear: **work start time + (15 \* run attempt count)**
- For exponential: **work start time + Math.scalb(15, run attempt count — 1)**

The **work start time** , is when the work was first executed (the 1st run attempt).

**Run attempt count** is how many times the WorkManager has tried to execute an specific Work.

Also note that the maximum delay will be capped at **WorkRequest.MAX\_BACKOFF\_MILLIS** and take into consideration that a retry will only happen if returning **WorkerResult.RETRY**

{% gist https://gist.github.com/magdamiu/bdf3165ba7e9230a9b462b7b6eea7c15 %}

#### 4️⃣ Chaining work

![](https://cdn-images-1.medium.com/max/960/1*wpZBIbI4IbBJ-82Fq3k01g.png)

Sometimes it is necessary to run some tasks in parallel or to chain them one after another one, or even to create groups of tasks chained or in parallel. These features are available also in WorkManager library.

The code for the previous scheme looks like this:

{% gist https://gist.github.com/magdamiu/edb91686b34541aa2702b6d5432b8c1a %}

![](https://cdn-images-1.medium.com/max/960/1*eRRNvrcCDVfDWxxjggCB6w.png)<figcaption>Parallel execution for Task 1 and Task 2</figcaption>

{% gist https://gist.github.com/magdamiu/c8f837f40f8ad884a6a7a25be12f7fb9 %}

![](https://cdn-images-1.medium.com/max/960/1*KcdLk2rfVucHag8z-nu2Pg.png)<figcaption>Chained tasks and parallel chains</figcaption>

{% gist https://gist.github.com/magdamiu/1c284f5371c3911f39840fe61a84e820 %}

#### 5️⃣ Merge inputs and outputs

Like we already saw when we chain the work the outputs are inputs of the tasks, but they should be merged somehow in order to get the correct data. To do the merge we have 2 main strategies in place that are actually the provided implementations of the abstract class [_InputMerger_](https://developer.android.com/reference/androidx/work/InputMerger):

- [_ArrayCreatingInputMerger_](https://developer.android.com/reference/androidx/work/ArrayCreatingInputMerger.html)
- [_OverwritingInputMerger_](https://developer.android.com/reference/androidx/work/OverwritingInputMerger.html)

![](https://cdn-images-1.medium.com/max/960/1*TBUwEHkiW-ugdIWOLEtNAw.png)

![](https://cdn-images-1.medium.com/max/960/1*PQW2ll-xY0F3yjmI9M_QkQ.png)

![](https://cdn-images-1.medium.com/max/960/1*f5gDm56-MNyuWZvB-WD8pA.png)

#### 6️⃣ Threading options in WorkManager

![](https://cdn-images-1.medium.com/max/960/1*G-0HnmY1OSZFTCdS9ypFdQ.png)

1. ListenableWorker
2. Worker
3. CoroutineWorker
4. RxWorker
5. Our own implementation :)

![](https://cdn-images-1.medium.com/max/960/1*kLlOJGwrRupYGXQlb_fgXA.png)

🧵 **_ListenableWorker_**

**Overview**

- A ListenableWorker only signals when the work should start and stop
- The start work signal is invoked on the main thread, so we go to a background thread of our choice manually
- A ListenableFuture is a lightweight interface: it is a Future that provides functionality for attaching listeners and propagating exceptions

**Stop work**

- It is always cancelled when the work is expected to stop. Use a CallbackToFutureAdapter to add a cancellation listener

🧵 **_Worker_**

**Overview**

- Worker.doWork() is called on a background thread, synchronously
- The background thread comes from the Executor specified in WorkManager’s Configuration, but it could also be customised

**Stop work**

- Worker.onStopped() is called. This method could be overridden or we could call Worker.isStopped() to checkpoint the code and free up resources when necessary

🧵 **_CoroutineWorker_**

**Overview**

- For Kotlin users, WorkManager provides first-class support for **coroutines**
- Instead of extending Worker, we should extend CoroutineWorker
- CoroutineWorker.doWork() is a suspending function
- The code runs on Dispatchers.Default, not on Executor (customisation by using CoroutineContext)

**Stop work**

- CoroutineWorkers handle stoppages automatically by cancelling the coroutine and propagating the cancellation signals

🧵 **_RxWorker_**

**Overview**

- For RxJava2 users, WorkManager provides interoperability
- Instead of extending Worker, we should extend RxWorker
- RxWorker.createWork() method returns a Single<Result> indicating the Result of the execution, and it is called on the main thread, but the return value is subscribed on a background thread by default. Override RxWorker.getBackgroundScheduler() to change the subscribing thread.

**Stop work**

- Done by default

#### 🎉WorkManager — Recap

- WorkManager is a wrapper for the existing background processing solutions
- Create one time or periodic work requests
- Identify our tasks by using ids, tags and unique names
- Add constraint, delay and retry policy
- Use input/output data and merge them
- Create chains of tasks
- Use the available threading options or create your own

That’s all folks! 🐰 Enjoy and feel free to leave a comment if something is not clear or if you have questions. And if you like it please 👏 and share !

Thank you for reading! 🙌🙏😍✌

* * *