Doing work with Android’s new WorkManager

Nikki Porter
Big Nerd Ranch
Published in
4 min readMay 23, 2018

Google announced a really exciting feature at this year’s Google I/O that allows developers to perform background tasks that would traditionally require detailed knowledge of various API levels and the background task libraries available for those APIs. WorkManager offers up the functionality that you would get from other APIs such as JobScheduler, FirebaseJobDispatcher, AlarmManager and Services, without the overhead of having to research which one is available for your device or API. — Rafael Moreno Cesar

If you’ve been around the block, you’ve probably seen a few Android versions come and go along with different ways to do work in the background. These APIs have always been hard to keep up with as Google added new features and deprecated old ones. The documentation was unclear about the right way of doing work on a background thread.

Consider trying to run a long running task using a JobScheduler that is scheduled to start your Job. The system will start your JobService when the time comes, but the minimum SDK that you can use with JobScheduler is buggy at 21 and is actually usable starting at 23. You might be targeting devices from SDK 21, so you’d also need to use a JobDispatcher for devices using your app at that API level. Since this JobSchedulermight not be available to you you could use the FirebaseJobDispatcher, but it requires play services which means that you’d be leaving out a ton of non Google devices that run Android. Depending on what you’re doing, it might make sense to use the AlarmManager but it’s not always the best choice. As possibly your final solution you might use a regular IntentService, but according to the Google docs

Note: If your app targets API level 26 or higher, the system imposes restrictions on running background services when the app itself isn’t in the foreground. In most cases like this, your app should use a scheduled job instead.

So now we’re back to where we started. In the past, choosing the best background scheduler has been hard, and this is why the new WorkManager is so great. It chooses the appropriate way to run your task based on app state and the API level.

WorkManager Components

  • WorkManager — receives the work with specific arguments and enqueues that work.
  • Worker — implements doWork() which executes the functionality on the background thread.
  • WorkRequest — represents an individual task. It will tell you which Worker is enqueued as well as what constraints it needs to meet in order for it to run. WorkRequest is an abstract class that you’ll be using with OneTimeWorkRequest or PeriodicWorkRequest.
  • WorkStatus — provides data for each WorkRequest object.

Let’s get hands on now with an example putting this all together.

Create your class extending Worker and implement the doWork() method.

class YourWorker: Worker {
override fun WorkerResult doWork() {
//do the work you want done on the background in here

return WorkerResult.SUCCESS
}
}

Having set up the work you want to get done, you would then call the WorkManager in order to queue up the work you want to execute. You can specify constraints that will dictate under what conditions the work will get done.

val work: OneTimeWorkRequest  = OneTimeWorkRequest.Builder(YourWorker::class.java).build()
WorkManager.getInstance().enqueue(work)

Because we are using a OneTimeWorkRequest and there were no constraints specified. The WorkManager runs the task immediately.

If we wanted to, we could limit our WorkManager to run our request one time only if we have a network connection and our device is currently charging.

val constraints: Constraints = Constraints.Builder()
.setRequiredNetworkType(NetworkType.CONNECTED)
.setRequiresCharging(true)
.build()

And the way we set up our work request would only change to accept these constraints

val work: OneTimeWorkRequest = OneTimeWorkRequest.Builder(SomeWorker::class.java).setConstraints(constraints).build()

If you wanted the work to happen more than once, there is the previously mentioned PeriodicWorkRequest for that as well. You can set it up in a very similar fashion, but you’d just specify a timer interval that you’d want the work to run on.

val recurringWork: PeriodicWorkRequest = PeriodicWorkRequest.Builder(YourWorker::class.java, 3, TimeUnit.HOURS).build()
WorkManager.getInstance().enqueue(recurringWork)

The wonderful thing about this API is that you don’t have to write any device logic or worry about selecting the best API for running these tasks. WorkManager has been doing all of that work for you!

But wait, there’s more!

If you wanted to run multiple tasks that are doing background thread work, we could chain together those tasks by creating a sequence of OneTimeWorkRequests with our WorkManager

WorkManager.getInstance().beginWith(firstWork)
.then(secondWork)
.then(thirdWork)
.enqueue()

If at any point one task fails, then the whole sequence will end.

This post just touches the surface on chaining these work requests. There are multiple ways to combine and run these tasks in parallel that you should explore.

Google keeps us on our toes with their continuous improvements to the framework, and hopefully by now you’re giddy with excitement to get started exploring the work you can do with Android’s new WorkManager.

Check out more blogs at bignerdranch.com/blogs

--

--