Using Android WorkManager

Kayvan Kaseb
Software Development
8 min readMay 26, 2020

--

The photo is provided by Unsplash

Nowadays, WorkManager is one of the Android Architecture Components and also a part of Android Jetpack as a new approach for developing modern Android apps. As a matter of fact, the WorkManager API is a suitable and recommended replacement for all previous Android background scheduling APIs. WorkManager is an API that makes it easy to schedule deferrable, asynchronous tasks, which are expected to run even if the app exits or the device restarts. This essay will discuss some main concepts in working with WorkManager, and explain some key steps for implementing in an Android app as well.

Introduction and Overview

Practically, your app will not always be in the foreground; however, you still need to do some significant background works such as downloading updates, and syncing with your server. Currently, there are a number of existing APIs for this purpose with their own particular use cases as follow: JobScheduler, Loader, Service, AsyncTask, Firebase JobDispatcher, GCM Network Manager, and AlarmManager.

In fact, before discussing what background execution is, we require to have a clear vision toward understanding an app to be in the foreground. An app is considered to be in the foreground if one of the following cases would be accomplished:

  1. The Android app has a visible activity.

2. The Android app has a foreground service.

3. Another foreground application is associated to the app by binding to one of its services, or using one of its content providers.

4. IME

5. Wallpaper service

6. Notification listener

7. Voice or text service

8. Music application when streaming music to your car.

As a result, if none of those situations is correct, the Android app is recognized to be in the background. Running tasks in the background consumes a device’s limited resources such as RAM and battery. This leads to affect user experiences . For instance, background tasks may diminish the battery life of the device at times such as watching a video, playing a game, or using the camera. Thus, to enhance battery life and give an appropriate user experience, Android has introduced a lot of battery-saving features in recent releases. These features manage and balance the power usage of applications as follows:

  1. App Standby Buckets: It helps the system prioritize apps’ requests for resources based on how recently and how frequently the apps are used.

2. Background Service Limitations: It restricts background services from being run and consuming CPU/network in a hidden/non-visible way.

3. Doze and App Standby: It restricts Android app behavior when the screen is off, and the device is idle and not charging.

4. Background Location Limits: To reduce power consumption, Android 8.0 (API level 26) limits how frequently background apps can retrieve the user’s current location. Apps can receive location updates only a few times each hour.

As an Android developer, you have to work with these battery-saving features to make sure your background tasks run across API levels. This issue can add code complexity to your project. For instance, for working background task on all API levels, you may have these lines of codes:

if  (userAPILevel  >= VERSION_CODES.M) {      //Running background task on devices M+}  else if  (userAPILevel >= VERSION_CODES.LOLLIPOP) {      //Running background task on devices L+}  else if ( … ) {      //Rest of your codes
}

However, if you do not perform this matter properly, you will face that your background work will not run for on all devices. This is the exact case that WorkManager library could be helpful for addressing these issues. WorkManager is one of the Android Architecture Components and also is a part of Android Jetpack as a new approach for developing modern Android apps. For example, you might point your app to download new resources from the network occasionally. So, the downloading is a task and you can set up this task to run at an appropriate time based on the availability of the WiFi network or when the device is charging. Now, you can be able to schedule a task by using WorkManager

Scheduling tasks with WorkManager

Initially, WorkManager provides a unified solution for background works, and also covers Android’s power-saving features as well as the user’s API levels. It is backwards compatible to API level 14. In addition, it can be run with or without Google Play services. These unique features make it the recommended solution for most background work on Android. There are two key attributes that make a task suitable for WorkManager. First, that the task is deferrable, and second, that the task requires to be guaranteed to run.

WorkManager is an API that makes it easy to schedule deferrable, asynchronous tasks that are expected to run even if the app exits or the device restarts.

  1. Deferrable: The task can run later and is still useful.

Deferrable work is any task that is still useful even if it is not run immediately. So, sending analytic data to your server is wholly deferrable work; however, sending an instant message is not deferrable.

2. Guaranteed: The task runs even if the device restarts.

Guaranteed work means that the task will run if the application process is killed or the device is restarted. Thus, an important example for WorkManager would be backing up pictures to a server. This work can be deferred, but it should be guaranteed to run as well.

Besides, WorkManager could be paired with other APIs like Firebase Cloud Messaging to trigger background work. Thus; for example, when there is data for syncing on your server, you can be able to use an FCM message to notify your app and then perform the real syncing with WorkManager. Another key point is that even though WorkManager is a powerful strategy, background work cannot be a replacement for all approaches. This means WorkManager is not a replacement for Executors + Threadpools, Kotlin Coroutines, and RxJava. Additionally, WorkManager is not designed to trigger a work at an exact time. For achieving this goal, you will need to use an API like AlarmManager, or start a foreground service if your users expect your tasks to occur promptly.

The picture is provided by Google Documents

Step for implementation WorkManager to Schedule Tasks

There are some main steps for implementing WorkManager in your Android projects, which are represented in this section respectively.

Adding the WorkManager dependency

In fact, the KTX version of the library provides some Extension Functions in Kotlin. You can use the KTX version of WorkManager using this dependency app/build.gradle file:

dependencies { def work_version = "2.3.4"
implementation "android.arch.work:work-runtime-ktx:$work_version"
}

If you want to use the Java dependency, you must remove the “-ktx” from the above dependency.

Defining the Worker

In this step you should define what your task does by using a worker. All the code summarize into the doWork() method. Furthermore, Workers accept inputs and produce outputs, and both inputs and outputs are represented as key, value pairs. Another significant point is that a Worker always return a value for representing success, failure, or retry. For instance, if you want to upload an image with WorkManager, you should implement a class as follow:

The input and output are passed as Data that is essentially a map of primitive types and arrays. Data objects have some restrictions on the total size, which can be input and output. This is set by the MAX_DATA_BYTES. If you need to pass more data for input and output of your worker, you should set your data in another place like Room database.

Creating WorkRequest

In this step you should make a request by using a class that is called WorkRequest. The WorkRequest is basically a class for configuring when and how task will be run. As part of the WorkRequest, you can add Constraints, specify the input, and choose to run the work once (OneTimeWorkRequest) or periodically ( PeriodicWorkRequest). In uploading an image as an example, because this task is non-repeating work, OneTimeWorkRequest is used.

val imageData = workDataOf(Constants.KEY_IMAGE_URI to imageUriString) 
val uploadWorkRequest = OneTimeWorkRequestBuilder<UploadWorker>()
.setInputData(imageData)
.build()

Furthermore, if you do not always run promptly because of checking for checking for network connection on device, you can do this matter by adding a Constraints object as follows:

val constraints = Constraints.Builder()  
.setRequiresBatteryNotLow(true)
.setRequiredNetworkType(NetworkType.CONNECTED)
.setRequiresCharging(true)
.setRequiresStorageNotLow(true)
.setRequiresDeviceIdle(true)
.build()

Enqueue the WorkRequest

At this point, you should schedule your work by adding this line of code, which includes WorkManager singleton instance and enqueue method for scheduling:

WorkManager.getInstance().enqueue(uploadWorkRequest)

Updating UI

At present, if you want to update the UI when your work finishes, you should use the getWorkInfoByIdLiveData method to obtain a WorkInfo LiveData. In fact, the WorkInfo is wrapped by LiveData for making it observable. WorkInfo has all of the information about the current state of your work, including the status of the work and the optional output. For example, if you want to show a message to the user when some works finishes successfully, you could set it up as follows:

WorkManager.getInstance(myContext).getWorkInfoByIdLiveData(uploadWorkRequest.id)
.observe(lifecycleOwner, Observer { workInfo ->
if (workInfo != null && workInfo.state == WorkInfo.State.SUCCEEDED) {
display Message("Work is done!")
}
})

Under the hood of WorkManager

As you know, WorkManager is backwards compatible to API level 14 and runs without Google Play Services. To make sure this issue, WorkManager chooses between JobScheduler and a combination of AlarmManager and Broadcast Receivers when running. To guarantee that the work keeps running, all information about enqueued work is kept in a WorkManager-managed database; therefore, it can be resumed if it is stopped.

All in all, WorkManager uses an underlying job dispatching service based on the following criteria under the hood:

Under the hood of WorkManager, the picture is provided by Google Documents

Threading Options

Basically, Worker uses an executor behind the scenes. So, if you want to manage threading in some other ways, there are RxWorker and CoroutineWorker as options for accomplishing. Also, for having more control on the process, you can make your own Worker class by extending ListenableWorker and defining your exact threading strategy.

Chains

WorkManager allows you to create and enqueue a chain of work that specifies multiple dependent tasks, and defines what order they should run in. This is particularly helpful when you require to run several tasks in a special order. For instance, an application runs image filters on three various images as parallel, then compresses those images together, and then uploads them.

WorkManager.getInstance(myContext)
.beginWith(listOf(filter1, filter2, filter3))
.then(compress)
.then(upload)
.enqueue()

Advantages of WorkManager

  1. You can schedule a task depending on the condition when they should run. So WorkManager give the guarantee that the task will be executed even when the device is rebooted.

2. It provides backward compatibility, which means you do not have to specify the device capabilities or choose an appropriate API.

3. You can detect and track the status of your tasks.

4. It provides task chaining. It means you can create a draft of your work, and enqueue one after the other using the WorkManager.

In conclusion

This essay considered some main concepts in using WorkManager based on Google resources, and defined some key steps for implementing in an Android project as well. Basically, WorkManager supports a unified solution for background works, and also covers Android’s power-saving features as well as the user’s API levels. So, you can schedule a task by using WorkManager efficiently in Android app development.

--

--

Kayvan Kaseb
Software Development

Senior Android Developer, Technical Writer, Researcher, Artist, Founder of PURE SOFTWARE YAZILIM LİMİTED ŞİRKETİ https://www.linkedin.com/in/kayvan-kaseb