[JET ROARING]
LYLA FUJIWARA: Your app won't always be in the foreground.
But you still need to do important background work
like downloading updates and syncing with your server.
Now, there are many existing APIs
for this, each with their own particular use cases.
Unfortunately, when these APIs are used incorrectly,
we see this happen.
To save power for users, Android has
introduced many battery-saving features in recent releases.
These features manage and balance
the power usage of apps.
As a developer, you need to work with these battery-saving
features to ensure your background
tasks run across API levels.
This adds code complexity.
But if you don't do this properly,
you risk your background work not running for all users.
This is where the WorkManager library comes in.
WorkManager provides a unified solution for background work,
taking Android's power-saving features and the user's API
level into account.
It's backwards compatible to API level 14, part
of Android Jetpack, and it runs with or without Google Play
services.
These features and more make it the recommended solution
for most background work on Android.
There are two key attributes that
make a task suitable for WorkManager--
first, that the task is deferrable,
and second, that the task needs to be guaranteed to run.
Deferrable work is any task which is still useful even
if it's not run immediately.
So sending analytic data to your server
is totally deferrable work.
But sending an instant message is not deferrable.
Guaranteed work means that the task
will run even if the app process is killed
or the device restarts.
So a great use case for WorkManager
would be backing up pictures to a server.
This work can be deferred, but it should also
be guaranteed to run.
WorkManager can be paired with other APIs,
like Firebase Cloud Messaging, to trigger background work.
So for example, when there is data
ready to sync on your server, you
can use an FCM message to notify your app
and then do the actual syncing with WorkManager.
While WorkManager is powerful, background work
isn't a one-size-fits-all approach.
So for example, while I've been talking a lot
about background work, what I don't mean
is background threading.
WorkManager works in conjunction with,
but is not a replacement for, Kotlin Coroutines, threadpools,
or libraries like RxJava.
WorkManager is also not designed to trigger work
at an exact time.
For that, you're going to need to use an API like AlarmManager
or start a foreground service if your users expect your tasks
to happen immediately.
For a complete view of modern background execution,
check out this blog post on the "Android Developer"
blog which I have linked below.
Now, let me show you how to actually create and do
some work.
Let's say that I want to upload a photo using WorkManager.
First, you define what your task does using a worker,
like this one.
All the code goes into the doWork method.
Then you make a request to do this work,
using a class called WorkRequest.
As part of the WorkRequest, you could add constraints,
specify the input, and choose to run the work once
or periodically.
The WorkRequest is basically a class
for configuring when and how your task will be run.
Since this is non-repeating work,
I'm going to go ahead and use a OneTimeWorkRequest.
I've added a constraint here that it should only
do this upload when there's actually network.
Finally, this passes in the URI of the photo as input data,
using WorkManager's Data Object.
Once you have a WorkRequest, you can enqueue it
by calling WorkManager.enqueue.
And well, that's it.
At this point, I know that this photo
will be uploaded at some point in the future when the network
constraint is met, even if the app is closed
or the phone restarts.
Now, let's say that I want the option of updating
the UI when my work finishes.
I can use the method getWorkInfoByIdLiveData
to get a WorkInfo LiveData.
The fact that the WorkInfo is wrapped by LiveData
makes it observable.
If you haven't used LiveData before,
you can read about it in the documentation linked below.
WorkInfo has all of the information
about the current state of my work,
including the status of the work and the optional output.
So back in doWork, I could return an output
and then add this LiveData observation code
to my UI to display the output when available.
So what's going on behind the scenes when you enqueue work?
As mentioned, WorkManager is backwards
compatible to API level 14 and runs
without Google Play services.
To ensure this, WorkManager chooses between JobScheduler
and a combination of AlarmManager and broadcast
receivers when running.
To guarantee that the work will keep running,
all of that information about enqueued work
is kept in a WorkManager-managed database
so that it can be resumed if it's ever stopped.
Now, by default, Worker does work off of the main thread,
using an executor behind the scenes.
If you want to handle threading in some other way,
there's RxWorker and CoroutineWorker, which
are available out of the box.
Or for even more control, you can make your own worker class
by extending ListenableWorker and defining
your exact threading strategy.
One area where WorkManager truly shines
is when you create chains of dependent work.
Let's say that I want to add a filter to multiple pictures,
compress those pictures together,
and then batch upload the compressed
file to share with the world.
Assuming you created all of your work requests
with the appropriate constraints,
the code to create this dependent chain of work
looks like this.
I enqueued the WorkRequests in the order
that I want them to run.
I've also enqueued these filter image WorkRequests
as a list, which causes them to run in parallel.
WorkManager will take care of passing through the output
and input in a chain.
So here, the output of these filter WorkRequests
will be passed as the input of the compressed WorkRequest.
There is a ton more that you could do with WorkManager.
You can specify things like periodic work
for work that needs to run repeatedly,
unique work, tagged work so that you can query or cancel
related work, and backoff policies for retrying work.
For even more features, tips, and tricks,
check out the "Working with Work Manager" talk linked below.
So to summarize, by using WorkManager,
you can enqueue one-off and periodic tasks
with constraints, chain tasks with input and output,
and run these chained tasks in parallel or sequentially,
display the state of your tasks using observation,
and customize WorkManager's threading strategy.
WorkManager does all of this while handling
complex compatibility issues, following
system health best practices, and guaranteeing your work
will run.
If you're ready to get working with WorkManager,
I've linked tons of helpful documentation, code labs,
presentations, and blog posts below.
Happy coding.
[JET ROARING]