Scheduling background tasks with Jetpack’s WorkManager

Android apps can work in the background in sever ways, but sometimes too much choice can be a bad thing. Android has a range of APIs and components for scheduling background work, and the “correct” approach can vary depending on the version of Android, and other factors like whether the device has access to Google Play Services.

Also read

Simplify asynchronous programming with Kotlin’s coroutines

Kotlin coroutines are still in the experimental phase, but they are quickly becoming one of the most popular features for developers that want to use asynchronous programming methods.
Most mobile apps have to perform long-running or …

For example, you can use JobScheduler to schedule background work, but only on Android 5.0 (API 21) and later. If you want your app to be compatible with earlier versions of Android, you could use Firebase JobDispatcher, but there’s a catch: JobDispatcher requires Google Play Services, and there’s plenty of Android users who don’t have access to Google Play Services, especially in China.

WorkManager is a new library for making scheduling and managing background work much less painful. Announced at Google I/O 2018 as part of Jetpack, it provides a new, straightforward way to handle background tasks — by doing all the hard work for you.

Let’s take a look at how to use WorkManager to schedule background work, run tasks in parallel, and improve the user experience by specifying different conditions that need to be met before a task can run.

Exploring Jetpack: What is WorkManager?

WorkManager is a job dispatching service scheduling tasks, and then forget about them. Once a task is scheduled, WorkManager will run it regardless of whether the user navigates away from the related screen, exits your application, or even reboots their device. This makes it ideal for tasks requiring guaranteed execution.

By default, WorkManager runs each task immediately, but you can also specify the conditions a device needs to fulfill before the task can run, including network conditions, charging status, and the amount of storage space available on the device. For example, you can reduce the amount of mobile data your app consumes by delaying data-intensive tasks until the device is connected to an unmetered network, or only perform battery-intensive tasks when the device is charging.

Android users can create shortcuts to any of their applications. It's a quick and easy process that just involves placing the app’s launcher icon onto the homescreen.
While this kind of shortcut does make it easier …

If WorkManager executes while your application is running, it’ll perform its work in a new background thread. If your application isn’t running, WorkManager will choose the most appropriate way to schedule the background task, based on factors such as the device’s API level and whether it has access to Google Play Services. In this way, WorkManager can provide the functionality of APIs like JobScheduler without requiring you to check the device’s capabilities and provide alternative solutions depending on the results. Specifically, WorkManager uses JobScheduler on devices running API 23 and later. On API 14-22 it’ll use either Firebase JobDispatcher, or a custom AlarmManager and BroadcastReceiver implementation, if Firebase isn’t available.

Since WorkManager is part of Jetpack, it’s backwards compatible to API level 14, so it’s ideal for scheduling background tasks across earlier versions of Android where solutions such as JobScheduler aren’t supported. It can also function with or without Google Play Services, so you can be confident your app will behave as expected, even in parts of the world where access to Google Play Services is restricted.

Once WorkManager is stable it’ll be the recommended task scheduler for tasks that require guaranteed execution. WorkManager isn’t intended to be a catch-all solution for every task you need to run off the main thread, so if a task doesn’t require guaranteed execution then you should use intent services or foreground services instead.

One time task, or recurring?

WorkManager supports two types of work:

OneTimeWorkRequest

To schedule a task that executes one time only, you need to create a OneTimeWorkRequest object, and then enqueue your task:

Since we haven’t specified any constraints, this task will run immediately.

PeriodicWorkRequest

You’ll want to repeat some tasks, like syncing your application’s data with a server once per day.

To create a recurring task, you use PeriodicWorkRequest.Builder to build a PeriodicWorkRequest object, specify the interval between each task, and then enqueue the PeriodicWorkRequest. Here we’re creating a task that will run once every 12 hours:

Making the switch to WorkManager

Let’s look at how you’d implement a few different WorkManager workflows, including how to create tasks that only run when specific constraints are met.

I’m going to create an app consisting of a button that will pass a task to WorkManager when clicked. To keep things simple, this task will print a message to Android Studio’s Logcat, but you can swap the Logcat portions of the code for any other task you had in mind.

Create a new project, then open its build.gradle file and add the WorkManager library as a project dependency:

Run your project on an Android device or Android Virtual Device (AVD), and give the “One Time Request” button a click. This task should immediately run in the background and print the “doWork called” message to Android Studio’s Logcat.

Setting some constraints: Controlling when a task runs

By default, WorkManager will perform each task immediately, but you can also specify constraints that need to be met before the work gets done. You can use it to delay intensive tasks until the device is idle, to avoid negatively impacting the user experience.

To set some rules about when a task should run, you’ll need to create a Constraints object using Constraints.Builder, and then specify the Constraint(s) that you want to use, such as .setRequiresDeviceIdle:

Wherever possible you should test WorkManager on an Android Virtual Device (AVD), as it’s usually easier to simulate different device conditions, rather than waiting for them to occur on your smartphone or tablet naturally.

To test this particular project’s battery constraint, follow these steps:

Install the application on an AVD.

Click the “More” icon in the strip of controls that appear alongside the emulator (where the cursor is positioned in the following screenshot).

Select “Battery” from the left-hand menu.

Open the “Charger connection” dropdown, and set it to “None.”

Open the “Battery status” dropdown, and set it to “Not charging.”

Make sure the “Charge level” is set to 100 percent.

Click the app’s “One Time Request” button.

Check Android Studio’s Logcat window; the “doWork called” message should have been printed, as normal.

Next, repeat this process with a low battery level:

Once again, click the “More” icon to open Android Studio’s “Extended controls” window.

Select “Battery” from the left-hand menu.

Drag the “Charge level” slider to 15 percent or lower.

Click the “One Time Request” button; nothing should happen.

Drag the slider to 100 percent, and the “doWork called” message should appear in Logcat.

This is also a good opportunity to see how WorkManager can run scheduled tasks, even when the user has exited your application:

Set the AVD’s “Charge level” slider to 15 percent.

Click the “One Time Request” button; no message should appear.

Exit your application.

Increase the “Charge level,” and the message should be printed, even though your application isn’t currently onscreen.

Get specific: Setting multiple constraints

Sometimes, you’ll have a task that should only run under very specific circumstances, for example you might want to delay an unusually intensive task until the device is charging, connected to the Internet and standing idle.

You can use WorkManager to build chains of constraints. Here we’re creating a task that will only run when the device is connected to an unmetered network and a power outlet:

You can put this application to the test by only meeting one of these constraints and checking whether the message still appears in Android Studio’s Logcat:

Install the updated project on your AVD.

Click the “More” button, followed by “Battery.”

Set the dropdowns to “Charger connection: AC charger” and “Battery status: Charging.”

Disconnect this emulated device from the Wi-Fi, by opening the AVD’s Settings application, selecting “Network & Internet,” and then pushing the Wi-Fi slider to the Off position.

Switch back to your application and give its “One Time Request” button a click. At this point, nothing should appear in Logcat, as the device successfully meets the first condition (charging) but doesn’t meet the second condition (connected to the network).

Navigate back to the device’s Settings > Network & Internet menu, and then push the Wi-Fi slider into the On position. Now that you’ve met both constraints, the message should appear in Android Studio’s Logcat panel.

Chaining tasks with WorkContinuation

Some of your tasks may depend on the successful completion of other tasks. You might want to upload your application’s data to a server, but only after that data has been compressed.

You can create chains of tasks, by calling WorkManager’s beginWith() method and passing it the first task in the chain. This will return a WorkContinuation object, which allows you to chain subsequent tasks, via the WorkContinuation.then() method. Finally, when enqueue this sequence using WorkContinuation.enqueue(), WorkManager will run all of your tasks in the requested order.

If you need to create more complex sequences, then you can join multiple chains using the WorkContinuation.combine() method.

Different constraints, for different tasks

You can combine constraints and chained tasks to create a sequence where each task waits until a different set of conditions are met. Our application could compress its data whenever storage space is low, and then wait until the device is connected to an unmetered network, before syncing this newly-compressed data with the server.

Here, I’ve updated my MainActivity so that request1 only runs when the device is charging, and request2 only runs when there’s an active network connection:

Wrapping up

So that’s how to use the new WorkManager API to schedule background work, including running tasks in parallel, creating chains of related tasks, and using constraints to specify exactly when a task should run.

Now that you’ve seen WorkManager in action, do you think it’s an improvement on Android’s previous schedulers? Let us know in the comments below!

Learn How To Develop Your Own Android App

Get Certified in Android App Development! No Coding Experience Required.

Android Authority is proud to present the DGiT Academy: the most detailed and comprehensive course covering every aspect of Android app development, run by our own Gary Sims. Whether you are an absolute beginner with zero coding knowledge or a veteran programmer, this course will guide you through the process of building beautiful, functional Android apps and bring you up to speed on the latest features of Android and Android Studio.

The package includes over 6 hours of high quality videos and over 60 different lessons. Reams of in-depth glossaries and resources, highly detailed written tutorials and exclusive access to our private slack group where you can get help directly from Gary and our other elite developers.

AA readers get an additional 60% off today. That's a savings of over $150. Claim your discount now using exclusive promo code: SIXTYOFF. This is your ticket to a lucrative future in Android App Development. What are you wating for?