Working with the WorkManager

Vinay
IVYMobility TechBytes
4 min readDec 27, 2021

In the previous article we looked into the android WorkManager, its features and benefits. Now we are going to see how to use it in real-time.

As traditional as it is in the android development, we need to add the following dependencies in the build.gradle file, first hand, depending upon the requirements of the developer to use the API in the project.

dependencies {

def work_version = "2.7.1"
// (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"
// optional - GCMNetworkManager support
implementation "androidx.work:work-gcm:$work_version"
// optional - Test helpers
androidTestImplementation "androidx.work:work- testing:$work_version"
// optional - Multiprocess support
implementation "androidx.work:work-multiprocess:$work_version"
}

In the above dependencies implementation, we can see there are separate versions for Java and Kotlin. A developer can choose according to the coding language.

Also we can see the optional implementations to support RxJava2, GCMNetworkManager, Multiprocess and for Test helpers too.

And post the gradle sync, its time to define the work to run.

Defining the work

Work using the WorkManager is defined using the class named Worker within which the doWork() method is available, which runs asynchronously on a background thread provided by WorkManager.

To create the necessary work for WorkManager to run, the Worker class is to be extended and the doWork() method should be overridden.

A simple example via Java would be like this:

public class UploadWorker extends Worker {   public UploadWorker(
@NonNull Context context,
@NonNull WorkerParameters params) {
super(context, params);
}
@Override
public Result doWork() {
// Do the work here(upload the images in this case)
uploadImages();
// Indicate whether the work finished successfully with the Result
return Result.success();
}
}

This example would make the tedious process of transferring a huge amount of byte-array data of images as simple and as flawless as possible.

Result mentioned in the above example is the return type in the WorkManager API. The doWork() method returns the Result to the WorkManager service mentioning whether the work has been succeeded, failed, and, in the case of failure, whether or not the work should be retried.

Below are the types of the Result:

* Result.success(): The work finished successfully.

* Result.failure(): The work failed.

* Result.retry(): The work failed and should be tried at another time according to its retry policy.

Creating a WorkRequest

Now that we’ve defined the work that needs to be executed. And in order to run, it must be scheduled to the WorkManager service.

WorkManager provisions developers with a lot of flexibility in how you schedule their work. One can schedule it to run over an interval of time(run periodically), or to run just once. Its upto the developer to choose which way the work should be run. This could be done using WorkRequest available in the WorkManager API.

To run the work just once, OneTimeWorkRequest can be used as in the below example:

WorkRequest uploadWorkRequest =
new OneTimeWorkRequest.Builder(UploadWorker.class).build();

The above syntax can be used for complex works.

For much simpler works, which requires no additional configuration, we can use the static method ‘from’, and below its syntax:

WorkRequest myWorkRequest = OneTimeWorkRequest.from(MyWork.class);

Submiting the WorkRequest

All set. And this is the final step. We need to submit WorkRequest to the WorkManager. For this, the API has another method known as enqueue().

It can be done as below:

WorkManager.getInstance(myContext).enqueue(uploadWorkRequest);

Work Constraints

In the previous article we saw the WorkManager API also provisions work constraints. Its one of the flexibilities a developer could have. Work constraints ensures that work is deferred until optimal conditions are met.

WorkManager API offers the following conditions:

NetworkType: Constrains the type of network required for your work to run. For example, Wi-Fi (UNMETERED).

BatteryNotLow: When set to true, your work will not run if the device is in low battery mode.

RequiresCharging: When set to true, your work will only run when the device is charging.

DeviceIdle: When set to true, this requires the user’s device to be idle before the work will run. This can be useful for running batched operations that might otherwise have a negative performance impact on other apps running actively on the user’s device.

StorageNotLow: When set to true, your work will not run if the user’s storage space on the device is too low.

In order to create a constraint, or a set of constraints and associate it with some work, we need to create an instance of Constraints the Contraints.Builder() and assign it to our WorkRequest.Builder().

If, for an example, we need the work to run only when the user’s device is both charging and on Wi-Fi, we can create the constraints as below:

Constraints constraints = newConstraints.Builder()
.setRequiredNetworkType(NetworkType.UNMETERED)
.setRequiresCharging(true)
.build();

And set those constraints to the WorkRequest as:

WorkRequest myWorkRequest = new OneTimeWorkRequest.Builder(MyWork.class)
.setConstraints(constraints)
.build();

Voila..! We’ve implemented a work using the WorkManager which runs in the background and capable of keeping both the developer and the device cool, and gets the job done seamlessly.

In the next article, lets look on how to run a work with multiple or say, several constrains, time delays and other features that exists in the WorkManager API.

Until then, happy coding..!

--

--