DEV Community

Magda Miu
Magda Miu

Posted on • Originally published at proandroiddev.com on

Workout your tasks with WorkManager — Advanced Topics

Workout your tasks with WorkManager — Advanced Topics

“WorkManager is a library for managing deferrable and guaranteed background work.”

In my previous two posts about WorkManage I covered topics like:

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

WorkManager mind map diagram

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

2️⃣ Get the status of a task

WorkInfo contains info about a particular WorkRequest

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 = ❤️

*Cancel a task *

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

4️⃣ Chaining work

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:

Parallel execution for Task 1 and Task 2

Chained tasks and parallel chains

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:

6️⃣ Threading options in WorkManager

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

🧵 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 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! 🙌🙏😍✌


Top comments (0)