WorkManager Tutorial for Android: Getting Started
- Understanding Background Work
- Types of Background Work
- Why WorkManager?
- Knowing When to Use WorkManager
- Getting Started
- Setting Up the WorkManager Library
- Understanding WorkManager Classes
- Creating Your First Background Task
- Writing the FilterWorker Code
- Instantiating and Configuring the Worker
- Checking the Results
- Chaining Tasks
- Writing the CompressWorker Code
- Chaining FilterWorker with CompressWorker
- Checking the Results
- Cleaning the Worker and Uploading the ZIP
- Checking the Results
- Starting Unique Work
- Replacing Existing Work of Picked Photos
- Observing Work
- Tagging a WorkRequest and Observing It
- Checking the Results
- Canceling Work
- Canceling the Picking Photos Work Sequence
- Understanding Constraints
- Adding a Network Connection Constraint
- Testing the Network Constraint
- Where to Go From Here?
At Google I/O 2018, Google announced the WorkManager library as part of the Android Jetpack component set. Moving forward, WorkManager replaces JobScheduler as Google’s recommended way to enqueue background tasks that are guaranteed to execute.
In this WorkManager tutorial, you’ll learn about the different types of background work and their respective uses. You’ll also implement a series of workers, each performing a different task. Finally, you will connect the tasks together using WorkManager task chaining.
Understanding Background Work
Background work is any app-related task that is not executed on the Android main (UI) thread.
Usually, you need to execute on a background thread because the task is an expensive operation — like applying filters to a bitmap — or the task depends on a network request to query or post data.
Because you don’t want to block the main thread, or you want the task to continue running even if you close the app, you dispatch the task to a background thread.
Types of Background Work
The types of background work can be categorized in two dimensions:
The vertical axis is the timing of the work: “Does the work need to be executed at an exact time or can it be deferred?”
The horizontal axis represents how relevant the work is: “Do you need a guarantee that the work will be executed?”
Depending on your use case, there are various approaches available:
- On the left, for tasks that don’t need a guarantee of execution, you can use ThreadPools, RxJava or coroutines.
- On the upper right, for exact timing and guaranteed execution, you should use a ForegroundService.
- On the lower right, for deferrable and guaranteed execution, you have several options: JobScheduler, Firebase JobDispatcher, and Alarm Manager + Broadcast receivers.
WorkManager falls into the category of guaranteed execution and deferrable.
Since Android Marshmallow, the Android team has started to put more focus on battery optimizations. The team introduced Doze mode and, later in Android Oreo, it introduced background service limits — just to mention a few. With Android Pie, the team continues to give attention to optimization and introduce new changes.
Until now, to perform background work, developers not only had to know about these battery optimizations, but also had to choose between the many ways to implement the work.
Internally, WorkManager uses the existing mentioned options to perform background work: JobScheduler, Firebase JobDispatcher, and Alarm Manager + Broadcast receivers.
Depending on the configuration of a given device that your app is installed on (OS version, Google Play services availability, etc.), WorkManager will choose an appropriate option and execute the work when it considers the optimum time to do so.
In doing so, WorkManager provides a simple and clean interface and “hides” the complexity of deferrrable but guaranteed background work from developers.
Knowing When to Use WorkManager
As was previously mentioned, WorkManager falls into the deferrable guaranteed execution category of background work.
A few example use cases:
- Uploading files to a server.
- Syncing data to/from a server and saving it to a Room database.
- Sending logs to a server.
- Executing expensive operations on data.
In this tutorial, you’ll learn how to execute these types of background tasks using WorkManager.
The project you’ll be working with, PhotoUploader, is an app to pick photos from your photo library and execute the following operations in the background:
- Apply a sepia filter to each image.
- Zip the filtered images.
- Upload the .zip file to a server.
Use the Download materials button at the top or bottom of this tutorial to download the starter project.
Once downloaded, open the starter project in Android Studio 3.2 Beta 1 or newer. When you build and run it, you’ll see the first screen shown here:
Currently, tapping on the “Pick Photos” button will let you pick one or more photos from your library. After that, it does nothing. You’ll write code to add the featured mentioned above to the app.
Reviewing the project, you’ll see that it consists of two files:
- MainActivity.kt: This is the main screen with a Pick Photos button.
- ImageUtils.kt: Contains the aforementioned operations that you’ll execute in the background.
Setting Up the WorkManager Library
Open the build.gradle file for the app module and add the following dependency:
Note: At the time of the writing of this tutorial, there’s an alpha04 version. However, parallel and chaining WorkRequests (to be explained later) won’t work. This is likely because the library is still alpha.
That’s all the setup you need to start using the library!
Understanding WorkManager Classes
Before adding code to the project, you’ll need to familiarize yourself with the following main classes that the WorkManager library contains:
- WorkManager: This is the main class that you’ll use to enqueue WorkRequests.
- Worker: You’ll need to subclass this to perform the task that will run in the background.
- WorkRequest: This represents the request of the task that will run. You’ll set the task through the Worker subclass. You can also specify constraints — for example, only run the task if the device has Internet connectivity. There are two main types of work requests: OneTimeWorkRequest, which executes the task just one time, and PeriodicWorkRequest, which executes your task periodically. The period of a PeriodicWorkRequest can be customized.
- WorkStatus: Whenever you need to know the status — running, enqueued, finished, etc., for example — of a particular WorkRequest, you can ask the WorkManager for it. It will provide a LiveData object containing one or more WorkStatus objects.
Creating Your First Background Task
For your first background task, you’ll create the FilterWorker. This worker will receive the URIs of the selected images and apply a sepia filter to them.
Note: In the following snippets, file imports won’t be shown, as you’ll be focusing on the actual code required to implement tasks. The worker-related imports start with the package androidx so, when importing, make sure you choose the correct one.