Optimize location for battery

The Background Location
Limits introduced in
Android 8.0 (API level 26) have brought renewed focus to the subject of how
location services usage affects battery drain. This page addresses some location
services best practices and what you can do now to make your apps more battery
efficient. Applying these best practices benefits your app regardless of the
platform version it is running on.

The background location limits in Android 8.0 introduced the following changes:

Background location gathering is throttled and location is computed, and
delivered only a few times an hour.

Wi-Fi scans are more conservative, and location updates aren't computed when
the device stays connected to the same static access point.

Geofencing responsiveness changes from tens of seconds to approximately two
minutes. This change noticeably improves battery performance—up to 10 times
better on some devices.

This page assumes you’re using the Google Location Services
APIs, which offer higher accuracy and
impose a lighter battery burden than the framework location
APIs. In
particular, this page assumes familiarity with the fused location provider
API,
which combines signals from GPS, Wi-Fi, and cell networks, as well as
accelerometer, gyroscope, magnetometer and other sensors. You should also be
familiar with the geofencing
API, which is built
on top of the fused location provider API, and is optimized for battery
performance.

Understand battery drain

Location gathering and battery drain are directly related in the following
aspects:

Accuracy: The precision of the location data. In general, the higher the
accuracy, the higher the battery drain.

Frequency: How often location is computed. The more frequent location is
computed, the more battery is used.

Latency: How quickly location data is delivered. Less latency usually requires
more battery.

Accuracy

You can specify location accuracy using the
setPriority()
method, passing one of the following values as the argument:

PRIORITY_HIGH_ACCURACY
provides the most accurate location possible, which is computed using as
many inputs as necessary (it enables GPS, Wi-Fi, and cell, and uses a
variety of
Sensors), and may cause
significant battery drain.

PRIORITY_NO_POWER
receives locations passively from other apps for which location has
already been computed.

The location needs of most apps can be satisfied using the balanced power or low
power options. High accuracy should be reserved for apps that are running in the
foreground and require real time location updates (for example, a mapping
app).

Frequency

You can specify location frequency using two methods:

Use the
setinterval()
method to specify the interval at which location is computed for your app.

Use the
setFastestInterval()
to specify the interval at which location computed for other apps is
delivered to your app.

You should pass the largest possible value when using setInterval(). This is
especially true for background location gathering, which is often a source of
unwelcome battery drain. Using intervals of a few seconds should be reserved for
foreground use cases. The background location limits introduced in Android 8.0
enforce these strategies, but your app should strive to enforce them on Android
7.0 or lower devices.

Latency

You can specify latency using the
setMaxWaitTime()
method, typically passing a value that is several times larger than the interval
specified in the
setInterval()
method. This setting delays location delivery, and multiple location updates may
be delivered in batches. These two changes help minimize battery consumption.

If your app doesn’t immediately need a location update, you should pass the
largest possible value to the setMaxWaitTime() method, effectively trading
latency for more data and battery efficiency.

When using geofences, apps should pass a large value into the
setNotificationResponsiveness()
method to preserve power. A value of five minutes or larger is recommended.

Location use cases

This section describes some typical location-gathering scenarios, along with
recommendations for optimal use of the geofencing and fused location provider
APIs.

User visible or foreground updates

Example: A mapping app that needs frequent, accurate updates with very low
latency. All updates happen in the foreground: the user starts an activity,
consumes location data, and then stops the activity after a short time.

The interval specified in the
setInterval()
method depends on the use case: for real time scenarios, set the value to few
seconds; otherwise, limit to a few minutes (approximately two minutes or
greater is recommended to minimize battery usage).

Knowing the location of the device

Example: A weather app wants to know the device’s location.

Use the
getLastLocation()
method, which returns the most recently available location (which in rare
cases may be null) . This method provides a simple way of getting location and
doesn't incur costs associated with actively requesting location updates. Use
in conjunction with the
isLocationAvailable()
method, which returns true when the location returned by
getLastLocation()
is reasonably up-to-date.

Starting updates when a user is at a specific location

Example: Requesting updates when a user is within a certain distance of
work, home, or another location.

Use geofencing in conjunction with fused location provider updates. Request
updates when the app receives a geofence entrance trigger, and remove updates
when the app receives a geofence exit trigger. This ensures that the app gets
more granular location updates only when the user has entered a defined
area.

The typical workflow for this scenario could involve surfacing a notification
upon the geofence enter transition, and launching an activity which contains
code to request updates when the user taps the notification.

Starting updates based on the user’s activity state

Example: Requesting updates only when the user is driving or riding a
bike.

Use the Activity Recognition
API in
conjunction with fused location provider updates. Request updates when the
targeted activity is detected, and remove updates when the user stops
performing that activity.

The typical workflow for this use case could involve surfacing a
notification for the detected activity, and launching an activity which
contains code to request updates when the user taps the notification.

Long running background location updates tied to geographical areas

Example: The user wants to be notified when the device is within proximity
of a retailer.

If you're tracking dwell transitions, use the
setLoiteringDelay()
method passing a value of approximately five minutes or less.

Use the
setNotificationResponsiveness(),
passing a value of approximately five minutes. However, consider using a value
of approximately ten minutes if your app can manage the extra delay in
responsiveness.

An app may only register a maximum of 100 geofences at a time. In a use
case where an app wants to track a large number of retailer options, the app
may want to register large geofence (at the city level) and dynamically
register smaller geofences (for locations within the city) for stores within
the larger geofence. When user enters a large geofence, smaller geofences can
be added; when the user exits the larger geofence, the smaller geofences can
be removed and geofences could be re-registered for a new area.

Long running background location updates without a visible app component

Example: An app that passively tracks location

Note: Consider if you really need to collect location in the background, since
this can lead to undesirable battery drain. Also, consider geofencing as an
option, since geofencing APIs are optimized for performance.

If you need more location data, use passive location by calling the
setFastestInterval()
method passing a smaller value than what you pass to
setInterval().
When combined with the
PRIORITY_NO_POWER
option, passive location can opportunistically deliver location computed by
other apps at no extra cost.

Moderate frequency by adding some latency, using the
setMaxWaitTime()
method. For example, if you use the setinterval() method with a value of
approximately 10 minutes, you should consider calling setMaxWaitTime() with
a value between 30 to 60 minutes. Using these options, location is computed
for your app approximately every 10 minutes, but the app is only woken up
every 30 to 60 minutes with some location data available as a batch update. This
approach trades latency for more data available and better battery
performance.

Frequent high accuracy updates while the user interacts with other apps

Example: A navigation or fitness app that continues to work when the user
either turns off the screen or opens a different app.

Use a foreground service. If expensive work is potentially going to be done
by your app on behalf of the user, making the user aware of that work is a
recommended best practice. A foreground service requires a persistent
notification. For more information, see Notifications
Overview.

Location best practices

Implementing the best practices in this section help reduce the battery usage of
your app.

Set timeouts

To guard against battery drain, set a reasonable timeout when location updates
should stop. The timeout ensures that updates don't continue indefinitely, and
it protects the app in scenarios where updates are requested but not removed
(for example, because of a bug in the code).

For a fused location provider request, add a timeout by calling
setExpirationDuration(),
which receives a parameter that represents the time in milliseconds since the
method was last called. You can also add a timeout by calling
setExpirationTime(),
which receives a parameter that represents the expiration time in milliseconds
since the system last boot.

Batch requests

For all non-foreground use cases, batch multiple requests together. You can use
the
setInterval()
method to specify the interval at which you would like location to be computed.
Then, use the
setMaxWaitTime()
method to set the interval at which location is delivered to your app. The
value passed to the setMaxWaitTime() method should be a multiple of the value
passed to the setInterval() method. For example, consider the following
location request:

Java

In this case, location is computed roughly every ten minutes, and approximately
six location data points are delivered in a batch approximately every hour.
While you still get location updates every ten minutes or so, you conserve
battery because your device is woken up only every hour or so.

Use passive location updates

In background use cases, it is a good idea to throttle location updates. Android
8.0 limits enforce this practice, but apps running on older devices should
strive to limit background location as much as possible.

It is likely that while your app is in the background, another app may be
frequently requesting location updates in the foreground. Location services
makes these updates available to your app. Consider the following location
request, which opportunistically consumes location data: