From Punched Cards to Prompts
AndroidIntroduction When computer programming was young, code was punched into cards. That is, holes were punched into a piece of cardboard in a format...
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 – 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 OneTimeWorkRequest
s 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.
Introduction When computer programming was young, code was punched into cards. That is, holes were punched into a piece of cardboard in a format...
Jetpack Compose is a declarative framework for building native Android UI recommended by Google. To simplify and accelerate UI development, the framework turns the...
Big Nerd Ranch is chock-full of incredibly talented people. Today, we’re starting a series, Tell Our BNR Story, where folks within our industry share...