fbpx

Blogs from the Ranch

< Back to Our Blog

Doing work with Android’s new WorkManager

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.

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 JobScheduler might 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.

Not Happy with Your Current App, or Digital Product?

Submit your event

Let's Discuss Your Project

Let's Discuss Your Project