Doing background work with WorkManager - Part 2

Welcome back to part two of this article, if you haven't checked out part one, you can do so here. In part one I introduced the WorkManager API, its features, and best practices on using the API. In this part, we are going to create our first deferrable task using the WorkManager API (check out part one if you don't know what deferrable is). Without much further ado, let's get started.

1. Getting started

To use the WorkManager API, we first need to add Gradle dependencies to our module, in this case, the app module. As of the time of this writing, the latest stable version of WorkManager is 2.5.0. Depending on your language of choice, add the following dependencies:

def work_version = "2.5.0"

    // (Java only)
    implementation "androidx.work:work-runtime:$work_version"

    // Kotlin + coroutines
    implementation "androidx.work:work-runtime-ktx:$work_version"

    // optional - RxJava2 support
    implementation "androidx.work:work-rxjava2:$work_version"

2. Creating the worker class

The entry point for every work executed by WorkManager is a method called doWork() and to get access to this method, we have to create a class that extends the Worker class and implements the doWork() method.

class TaskWorkManager (val context: Context, val params: WorkerParameters) : Worker(context, params) {

    @Override
    fun doWork(): Result {

        return Result.success()   
    }
}

3. Creating the work request

Part of the flexibilities of WorkManager is that you can create work that only runs once or work that runs periodically.

One-off Work

Creating an instance of the OneTimeWorkRequest class does this for us effectively using the builder pattern.

val oneOffRequest = OneTimeWorkRequest.Builder(TaskWorkManager::class.java)
                .setInitialDelay(10, TimeUnit.SECONDS)
                .build()

The above code snippet creates a one-off work request that executes 10 seconds after it is triggered.

We can then enqueue the work using the enqueue() method from the WorkManager class passing the oneOffRequest variable:

WorkManager.getInstance(this).enqueue(oneOffRequest)

The getInstance() method takes a Context as a parameter so passing the this reference of an Activity does justice to that.

Periodic Work

Like one-off work requests, we use the PeriodicWorkRequest class to create a periodic work following the builder pattern:

val periodicRequest = PeriodicWorkRequest.Builder(TaskWorkManager::class.java, 20, TimeUnit.SECONDS)
                .setInitialDelay(10, TimeUnit.SECONDS)
                .addTag("periodic")
                .build()

The above code snippet creates a periodic work request with a tag name periodic that runs 10 seconds after it is triggered and executes the work afterward every 20 seconds.

Similar to enqueuing a one-off work, we can also enqueue our periodic work:

WorkManager.getInstance(this).enqueueUniquePeriodicWork("periodic", ExistingPeriodicWorkPolicy.REPLACE, periodicRequest)

As usual, the getInstance() method takes a Context and calls the enqueueUniquePeriodicWork() method taking our periodicRequest variable, a tag that helps WorkManager to identify work requests, and a work policy that could be:

  • ExistingPeriodicWorkPolicy.REPLACE: Canceling or deleting any uncompleted work that has the same tag.
  • ExistingPeriodicWorkPolicy.KEEP: Doing nothing when any uncompleted work with the same tag is encountered.

4. Doing the work

After all these, everything else becomes easy because of WorkManager's ease of use. We can now specify the kind of work or task we want to perform within the doWork() method. It could be to trigger a notification or database sync, WorkManager does all this for us behind the scene while following best practices of managing system resources.

The doWork() method returns one of:

  • Result.sucess(): Work completed successfully.
  • Result.failure(): Work failed.
  • Result.retry(): Work failed but should be retried some other time based on a retry policy specified.

Final words

Based on our use case, we may decide to create one-off or periodic work requests, leveraging WorkManager's capabilities in doing this goes a long way to making life easy for us as developers. As WorkManager makes our lives easy, this is just a tiny bit of what WorkManager has to offer. Other concepts like adding Work constraints, Retry Policies, etc are parts of what we can use WorkManager for.

Additional Resources

JPRGo9sO7.gif

Thank you for reading, if you found it useful, do not hesitate to like and share as others may find it useful as well. If you have questions or feedback for me, kindly drop them in the comments or send me a direct message on Twitter or LinkedIn, I'll be happy to connect with you.