LYLA FUJIWARA: You need to run background processes,
whether it's syncing with the server for the freshest content
or crunching data for your app.
However, running background processes
leads to a tricky compromise for the operating system.
Even if 20 apps have requested very important background work,
the app that the user is actually interacting with
needs to run smoothly.
Android Oreo introduces a radically different way
to think about background services.
Apps cannot run freely in the background.
This has implications for apps launched
from an implicit broadcast, as well as
apps starting services in the background.
Here's a quick list of affected APIs.
Location APIs are also affected, but I'm not
going to be covering these now.
More details on location updates are in the notes below.
These changes are true for all apps targeting
O. But even if you don't target O,
users can turn these limitations on,
so you need to be aware of these changes anyways.
First on the list of background behavior changes are services.
Calling start service from the background
will cause an illegal state exception.
Now this does not affect services started
when your app is visible and in the foreground,
nor does it affect bound services.
Here are a few more situations where the app is
considered in the foreground.
When your app moves from the foreground to the background,
there is a short grace period before your services shut down.
The service shuts down as if it had called stop self.
Now these changes affect everything that is a service.
So are IntentServices affected?
Well, yes.
Are Pending services affected?
Not when they are created, but when they are sent, so yes.
This even affects services you start in the background
that you intend to promote to the foreground.
The good news is that there are a few options
for saving your services.
Unless your app is an alarm clock app,
90% of the time your best option is to replace your background
service with a scheduled job.
While you are no longer allowed to start services
in the background, job scheduling
could do background work on your behalf.
This allows the framework to take
all of the scheduled jobs and their different constraints
and figure out which jobs to run when.
There are a number of different solutions for job scheduling
depending on your apps' needs.
I've linked to the documentation which explains the tradeoffs,
but if you want my advice, I would
look into using Firebase JobDispatcher and the new Job
IntentService.
Job IntentService is especially handy to replace IntentService.
Next is the temporary service whitelist.
There are a few special cases listed here
where the app will be temporarily whitelisted
and act for a short period of time
as if it's in the foreground.
If you want to trigger work when data on the server changes,
consider implementing Firebase Cloud Messaging on your server
and app.
If used a high priority FCM message,
you will receive that message immediately
even with the system is in Doze.
You will also get on that handy service whitelist
so you could start a service as if the app were
in the foreground.
Now if it's a normal priority FCM message,
the message is delivered when a user turns the device screen
on or during the Doze maintenance window.
You are not whitelisted to start services though.
So if your app receives both high and normal priority
messages, one approach is to try starting the service,
and if for any reason that fails,
have a fallback, such as starting a job.
If the service is something the user might
interact with or want to monitor,
you can make a foreground service instead.
Foreground services have a persistent notification
onscreen which informs the user that they're actually running.
Timers and navigation apps are common examples
of apps that employ foreground services effectively.
The thing is the old way of starting
a foreground service from the background will no longer work.
Instead, switch to the new API to start a foreground service.
The steps are first, use the new start foreground service
method.
This creates a background service
that you must immediately promote to the foreground.
Within the service, make a notification.
Your foreground service notification
should always be of low importance
or higher so that it's actually visible to the user.
It should not be of mid importance.
The final step is to have the service promote itself
to the foreground using start foreground and the notification
that you just made.
If you need a PendingIntent to start a foreground service,
you can use PendingIntent's new get foreground service method,
and then follow the same steps to promote it
to a foreground service.
If none of those options work for you,
you might consider deferring your work
until your app is in the foreground.
Now if you need to test your app under the new restrictions,
I've also included links below with the adb commands
to make the app run in the background
and to force background limitations for your app.
OK, let's switch to talking about implicit broadcast
receiver limitations.
Broadcast receivers that are statically
defined and listening for implicit broadcasts
will not receive those broadcasts.
Implicit broadcasts do not have the target component attribute
set.
And static broadcast receivers are defined
in the Android manifest.
Prior to Android Oreo, implicit broadcasts
would trigger any component listening for them
in the manifest.
Now, in research constrained situations,
this would cause memory thrashing
as a single broadcast triggering the creation
of a bunch of different components from different apps.
So here are your options for replacing
static implicit broadcast receivers.
Now there's a short list of exceptions,
so you should absolutely check that list first.
If the broadcast is on that list, it won't be affected
and it will function as normal.
This list contains things such as changing locale or plugging
in headphones.
The full document is linked.
If your broadcast is not the exception list,
you might be able to replace it with a job.
Jobs can be triggered by the following conditions, some
of which have been added in O. In particular,
content provider observers could trigger jobs
for a variety of situations, such as when the user saves
a new picture on their phone.
Now if part of your app is already
running when the broadcast is set,
you can switch to a dynamic broadcast receiver instead.
This means moving your broadcast receiver code out
of the manifest.
And then you create, register and unregister
it during runtime like I'm doing here.
Even though these situations focus on background processes,
the benefits will be felt for those
using your app in the foreground-- with less
jank and fewer crashes.
This will be even more impactful for users
who don't have access to the most expensive or fastest
hardware.
I've touched on a number of strategies and API changes.
If your app is affected and you want
to learn more and get started with code examples,
check out the documentation.
[MUSIC PLAYING]