Let’s Work manager do all the Background processing

Gaurav Bansal
5 min readMay 30, 2018

--

Background processing is integral part of android development.There are lot of things like Sending logs, upload data,Sync data etc are done by background tasks.There are plenty of ways to do these task such as Job Schedulers, Services, Loaders, AlarmManager etc.

Background task performer APIs

Android also introduced lot of battery optimization like Doze mode, App standby,Background service limitations etc that will put restrictions on background jobs.

When workManager-

Understanding Requirements- As we discussed there are plenty of ways to do background jobs,which one we should use for our task is very important decision.To decide this we have to clearly understand our requirements.There are two main things while deciding this first is timing and second is importance of work.

Background task requirements

Timing is important in background jobs, if we want to run our task instantly without any delay and task is initiated by user and supposed to be completed even user exit the app (That means Guaranteed execution )then we have to use foreground services. For task initiated by user but not need to be done when user back from that screen or exit app we can use ThreadPool or RxJava.There are some task also which can be delayed like sending logs and analytics data to server,pre-fetching data from server for these tasks we can use Jobscheduler or AlarmManager.

Why Work manager-

For background task which needs guaranteed execution and can be deferrable we have lot of options to do.We can use JobScheduler API but it is supported for API≥21 to overcome this we have FirebaseJobDispatcher library which provide backward compatibility upto API 14 but it requires Google Play services.So to avoid all these handling Work manager comes to rescue.
You don’t need to write device logic to figure out what capabilities the device has and choose an appropriate API; instead, you can just hand your task off to WorkManager and let it choose the best option.It is wrapper on all above concepts.

Work manager Features-

  • It provides Guaranteed execution with constraints(like only on Wifi or device plugged in).
  • When system put background restrictions it will not run.
  • It is backward compatible with or without google play services.It uses internally AlarmManager and BroadcatsReceiver for device which don’t have play services.
  • APIs are queryable, we can check work status.
  • APIs are also chainable.you can set up a chain of tasks; when one task finishes, WorkManager queues up the next task in the chain.

How to use work manager-

Add dependency-
dependencies {
implementation "android.arch.work:work-runtime:1.0.0-alpha02" }

Core classes-
Worker class- This class execute work.
Work Request class-Two flavours available of this class, OneTimeRequest for running task only single time and PeriodicWorkRequest for recurring work.

Example- First we create our class by extending worker class

public class MyWorker extends Worker {
@Override
public Worker.WorkerResult doWork() {

// Do the work here--in this case,
//This method will run on background thread
myWork();

// Indicate success or failure with your return value:
return WorkerResult.SUCCESS;

// (Returning RETRY tells WorkManager to try this task again
// later; FAILURE says not to try again.)
}
}

Now we will create OneTimeRequest object for a worker and then enqueue the task with WorkManager.

OneTimeWorkRequest compressionWork =
new OneTimeWorkRequest.Builder(MyWorker.class)
.build();
WorkManager.getInstance().enqueue(compressionWork);

While creating WorkRequest object we can also set constraints.
WorkManager chooses an appropriate time to run the task, balancing such considerations as the load on the system, whether the device is plugged in, and so on.

Observing Work

If you need to check on the task status, you can get a WorkStatus object by getting a handle to the appropriate LiveData<WorkStatus>. For example, if you want to check if the task has finished, you could use code like this:

WorkManager.getInstance().getStatusById(myWork.getId())
.observe(lifecycleOwner, workStatus -> {
// Do something with the status
if (workStatus != null && workStatus.getState().isFinished())
{ ... }
});

Canceling a Task

You can cancel a task after you enqueue it. To cancel the task, you need its work ID, which you can get from the WorkRequest object. For example, the following code cancels the myWork request from the previous section:

UUID myWorkId = myWork.getId();
WorkManager.getInstance().cancelByWorkId(myWorkId);

Note:-We can also set tag in work request using addTag() method and can use this tag for query work status or cancelling the task instead of using workId.We can also set multiple tags on single request.

Recurring tasks

You might have a task that you need to perform repeatedly. For example in news app syncing data every hour.

To create a recurring task, use the PeriodicWorkRequest.Builder class to create aPeriodicWorkRequest object, then enqueue the PeriodicWorkRequest the same way you would aOneTimeWorkRequest object.
For example

new PeriodicWorkRequest.Builder photoWorkBuilder =
new PeriodicWorkRequest.Builder(myWorker.class, 12,
TimeUnit.HOURS);
// ...if you want, you can apply constraints to the builder here...
// Create the actual work object:
PeriodicWorkRequest myWork = photoWorkBuilder.build();
// Then enqueue the recurring task:
WorkManager.getInstance().enqueue(myWork);

The WorkManager attempts to run your task at the interval you request, subject to the constraints you impose and its other requirements.

Chaining Work

Your app might need to run several tasks in a particular order. WorkManager allows you to create and enqueue a work sequence that specifies multiple tasks, and what order they should run in.

WorkManager.getInstance()
.beginWith(workA)
// Note: WorkManager.beginWith() returns a
// WorkContinuation object; the following calls are
// to WorkContinuation methods
.then(workB) // FYI, then() returns a new WorkContinuation instance
.then(workC)
.enqueue();

The WorkManager runs the tasks in the requested order, according to each task's specified constraints. If any task returns Worker.WorkerResult.FAILURE, the whole sequence ends.We can also pass multiple workRequest while enqueuing. If we pass several workRequest objects to a single method call, the WorkManager runs all of those tasks (in parallel) before it runs the rest of the sequence.

Unique work sequences

You can create a unique work sequence, by beginning the sequence with a call to beginUniqueWork()instead of beginWith(). Each unique work sequence has a name; the WorkManager only permits one work sequence with that name at a time. When you create a new unique work sequence, you specify what WorkManager should do if there's already an unfinished sequence with the same name:

  • Cancel the existing sequence and replace it with the new one
  • Keep the existing sequence and ignore your new request
  • Append your new sequence to the existing one, running the new sequence’s first task after the existing sequence’s last task finishes

How WorkManager works internally-

WorkManager uses an underlying job dispatching service when available based on the following criteria:

WorkManager Flow
  • Uses JobScheduler for API 23+
  • For API 14–22
    i)If using Firebase JobDispatcher in the app and the optional Firebase dependency, uses Firebase JobDispatcher
    ii)Otherwise, uses a custom AlarmManager + BroadcastReceiver implementation

For greater flexibility, we can pass arguments to your tasks and have the tasks return results.To check about this in detail see this.

WorkManager stable version will release soon so let’s wait till then or you can use the alpha version.

Also read posts about Mobile app system design

https://medium.com/@gauravbansal_13551/understanding-availability-from-mobile-app-system-design-perspective-135219e5646b

--

--