Updating TOC, adjusting page names...that sort of thing. Change-Id: I1a6cf66291344e5c210f287c1d38c65d621cfe91
427 lines
14 KiB
Plaintext
427 lines
14 KiB
Plaintext
page.title=Background Optimizations
|
||
page.metaDescription=New restrictions to implicit broadcasts.
|
||
page.keywords="android N", "implicit broadcasts", "job scheduler"
|
||
@jd:body
|
||
|
||
<div id="qv-wrapper">
|
||
<div id="qv">
|
||
<h2>
|
||
In this document
|
||
</h2>
|
||
|
||
<ol>
|
||
<li>
|
||
<a href="#connectivity-action">Restrictions on CONNECTIVITY_ACTION</a>
|
||
</li>
|
||
|
||
<li>
|
||
<a href="#sched-jobs">Scheduling Network Jobs on Unmetered
|
||
Connections</a>
|
||
</li>
|
||
|
||
<li>
|
||
<a href="#monitor-conn">Monitoring Network Connectivity While the App
|
||
is Running</a>
|
||
</li>
|
||
|
||
<li>
|
||
<a href="#persistant-monitor-conn">Persistent Monitoring of Network
|
||
Connectivity</a>
|
||
</li>
|
||
|
||
<li>
|
||
<a href="#media-broadcasts">Restrictions on NEW_PICTURE and
|
||
NEW_VIDEO</a>
|
||
</li>
|
||
|
||
<li>
|
||
<a href="#new-jobinfo">New JobInfo methods</a>
|
||
</li>
|
||
|
||
<li>
|
||
<a href="#new-jobparam">New JobParameter Methods</a>
|
||
</li>
|
||
|
||
<li>
|
||
<a href="#further-optimization">Further Optimizing Your App</a>
|
||
</li>
|
||
</ol>
|
||
</div>
|
||
</div>
|
||
|
||
<p>
|
||
Background processes can be memory and battery intensive. For example,
|
||
Implicit broadcasts frequently start background apps that have registered to
|
||
listen for them. This can have a substantial impact on device performance and
|
||
user experience.
|
||
</p>
|
||
|
||
<p>
|
||
To alleviate this issue, the N Developer Preview applies the following
|
||
restrictions:
|
||
</p>
|
||
|
||
<ul>
|
||
<li>Apps targeting the N Developer Preview will not receive {@link
|
||
android.net.ConnectivityManager#CONNECTIVITY_ACTION} broadcasts if they
|
||
register to receive them in their manifest. Apps running in the foreground
|
||
can still listen for {@code CONNECTIVITY_CHANGE} on their main thread with a
|
||
registered {@link android.content.BroadcastReceiver}.
|
||
</li>
|
||
|
||
<li>Apps will not be able to to send or receive {@code NEW_PICTURE} or {@code
|
||
NEW_VIDEO} broadcasts.
|
||
</li>
|
||
</ul>
|
||
|
||
<p>
|
||
The Android framework provides several solutions to mitigate the need for
|
||
these implicit broadcasts. For example, {@link android.app.job.JobScheduler}
|
||
and <a href=
|
||
"https://developers.google.com/android/reference/com/google/android/gms/gcm/GcmNetworkManager">
|
||
GcmNetworkManager</a> provide robust mechanisms to schedule network
|
||
operations when specified conditions, such as a connection to an unmetered
|
||
network, are met. You can also use {@link android.app.job.JobScheduler} to
|
||
react to changes to content providers. {@link android.app.job.JobInfo}
|
||
objects, built by the {@link android.app.job.JobInfo.Builder JobInfo.Builder}
|
||
class, encapsulate the parameters that {@link android.app.job.JobScheduler}
|
||
uses to schedule your job. When the conditions of the job are met, the system
|
||
executes this job on your app's {@link android.app.job.JobService}.
|
||
</p>
|
||
|
||
<p>
|
||
In this document, we will learn how to use alternative methods, such as
|
||
{@link android.app.job.JobScheduler}, to adapt your app to these new
|
||
restrictions.
|
||
</p>
|
||
|
||
<h2 id="connectivity-action">
|
||
Restrictions on CONNECTIVITY_ACTION
|
||
</h2>
|
||
|
||
<p>
|
||
Apps targeting the N Developer Preview do not receive {@link
|
||
android.net.ConnectivityManager#CONNECTIVITY_ACTION} broadcasts, even if they
|
||
register to receive them in their manifest. This could pose a problem for
|
||
apps that want to listen for network changes or perform bulk network
|
||
activities when the device connects to an unmetered network. Several
|
||
solutions to get around this restriction already exist in the Android
|
||
framework, but choosing the right one depends on what you want your app to
|
||
accomplish.
|
||
</p>
|
||
|
||
<p class="note">
|
||
<strong>Note:</strong> A {@link android.content.BroadcastReceiver} registered with
|
||
{@link android.content.Context#registerReceiver Context.registerReceiver()}
|
||
continues to receive these broadcasts on the app’s main activity thread.
|
||
</p>
|
||
|
||
<h3 id="sched-jobs">
|
||
Scheduling Network Jobs on Unmetered Connections
|
||
</h3>
|
||
|
||
<p>
|
||
When using the {@link android.app.job.JobInfo.Builder JobInfo.Builder} class
|
||
to build your {@link android.app.job.JobInfo} object, apply the {@link
|
||
android.app.job.JobInfo.Builder#setRequiredNetworkType
|
||
setRequiredNetworkType()} method and pass {@link android.app.job.JobInfo
|
||
JobInfo.NETWORK_TYPE_UNMETERED} as a job parameter. The following code sample
|
||
schedules a service when the device connects to an unmetered network and is
|
||
charging:
|
||
</p>
|
||
|
||
<pre>
|
||
public static final int MY_BACKGROUND_JOB = 0;
|
||
...
|
||
public static void scheduleJob(Context context) {
|
||
JobScheduler js =
|
||
(JobScheduler) context.getSystemService(Context.JOB_SCHEDULER_SERVICE);
|
||
JobInfo job = new JobInfo.Builder(
|
||
MY_BACKGROUND_JOB,
|
||
new ComponentName(context, JobService.class))
|
||
.setRequiredNetworkType(JobInfo.NETWORK_TYPE_UNMETERED)
|
||
.setRequiresCharging(true)
|
||
.build();
|
||
js.schedule(job);
|
||
}
|
||
</pre>
|
||
|
||
<p>
|
||
When the conditions for your job are met, your app receives a callback to run
|
||
the {@link android.app.job.JobService#onStartJob onStartJob()} method in the
|
||
specified {@code JobService.class}. To see more examples of {@link
|
||
android.app.job.JobScheduler} implementation, see the <a href=
|
||
"{@docRoot}samples/JobScheduler/index.html">JobScheduler sample app</a>.
|
||
</p>
|
||
|
||
<p>
|
||
Applications that use GMSCore services, and target Android 5.0 (API level 21)
|
||
or lower, should use <a href=
|
||
"https://developers.google.com/android/reference/com/google/android/gms/gcm/GcmNetworkManager">
|
||
GcmNetworkManager</a> and specify {@code Task.NETWORK_STATE_UNMETERED}.
|
||
</p>
|
||
|
||
<h3 id="monitor-conn">
|
||
Monitoring Network Connectivity While the App is Running
|
||
</h3>
|
||
|
||
<p>
|
||
Apps running in the foreground can still listen for {@code
|
||
CONNECTIVITY_CHANGE} with a registered {@link
|
||
android.content.BroadcastReceiver}. However, the {@link
|
||
android.net.ConnectivityManager} API provides a more robust method to request
|
||
a callback during specified network conditions.
|
||
</p>
|
||
|
||
<p>
|
||
{@link android.net.NetworkRequest} objects define the parameters of the
|
||
network callback in terms of {@link android.net.NetworkCapabilities}. You
|
||
create {@link android.net.NetworkRequest} objects with the {@link
|
||
android.net.NetworkRequest.Builder NetworkRequest.Builder} class. {@link
|
||
android.net.ConnectivityManager#registerNetworkCallback(android.net.NetworkRequest,
|
||
android.net.ConnectivityManager.NetworkCallback) registerNetworkCallback()}
|
||
then passes the {@link android.net.NetworkRequest} object to the system. When
|
||
the network conditions are met, the app receives a callback to execute the
|
||
{@link android.net.ConnectivityManager.NetworkCallback#onAvailable
|
||
onAvailable()} method defined in its {@link
|
||
android.net.ConnectivityManager.NetworkCallback} class.
|
||
</p>
|
||
|
||
<p>
|
||
The app continues to receive callbacks until either the app exits or it calls
|
||
{@link android.net.ConnectivityManager#unregisterNetworkCallback
|
||
unregisterNetworkCallback()}.
|
||
</p>
|
||
|
||
<h3 id="persistant-monitor-conn">
|
||
Persistent Monitoring of Network Connectivity
|
||
</h3>
|
||
|
||
<p>
|
||
The {@link android.net.ConnectivityManager} API also provides a method to
|
||
persistently monitor network connectivity. Due to its impact on performance,
|
||
however, it should be used with caution.
|
||
</p>
|
||
|
||
<p>
|
||
An app may use {@link
|
||
android.net.ConnectivityManager#registerNetworkCallback(android.net.NetworkRequest,
|
||
android.app.PendingIntent) registerNetworkCallback()} to register a {@link
|
||
android.app.PendingIntent} rather than a {@link
|
||
android.net.ConnectivityManager.NetworkCallback}. The request may outlive the
|
||
calling app and require it to start up in order to process a callback.
|
||
</p>
|
||
|
||
<p>
|
||
Before considering this option, think twice about whether this solution is
|
||
actually necessary, and consider the impact to performance and user
|
||
experience when doing so. Only apps that have a real need to start up on a
|
||
network change should implement this solution. Otherwise, every effort should
|
||
be taken to <a href="#connectivity-action">implement the alternatives</a>.
|
||
</p>
|
||
|
||
<h2 id="media-broadcasts">
|
||
Restrictions on NEW_PICTURE and NEW_VIDEO
|
||
</h2>
|
||
|
||
<p>
|
||
In the N Developer Preview, apps are not able to send or receive {@code
|
||
NEW_PICTURE} or {@code NEW_VIDEO} broadcasts. This restriction helps
|
||
alleviate the performance and user experience impacts when several apps must
|
||
wake up in order to process them. The N Developer Preview extends {@link
|
||
android.app.job.JobInfo} and {@link android.app.job.JobParameters} to provide
|
||
an alternative solution.
|
||
</p>
|
||
|
||
<h3 id="new-jobinfo">
|
||
New JobInfo methods
|
||
</h3>
|
||
|
||
<p>
|
||
To help trigger jobs on content URI changes, the N Developer Preview extends
|
||
the {@link android.app.job.JobInfo} API with the following methods:
|
||
</p>
|
||
|
||
<dl>
|
||
<dt>
|
||
{@code JobInfo.TriggerContentUri()}
|
||
</dt>
|
||
|
||
<dd>
|
||
Encapsulates parameters required to trigger a job on content URI changes.
|
||
</dd>
|
||
|
||
<dt>
|
||
{@code JobInfo.Builder.addTriggerContentUri()}
|
||
</dt>
|
||
|
||
<dd>
|
||
Passes a {@code TriggerContentUri} object to {@link
|
||
android.app.job.JobInfo}. The encapsulated content URI is monitored with a
|
||
{@link android.database.ContentObserver}. If there are multiple {@code
|
||
TriggerContentUri} objects associated with a job, the system provides a
|
||
callback even if it reports a change in only one of the content URIs.
|
||
</dd>
|
||
|
||
<dd>
|
||
Add the {@code TriggerContentUri.FLAG_NOTIFY_FOR_DESCENDANTS} flag to
|
||
trigger the job if any descendants of the given URI change. This flag
|
||
corresponds to the {@code notifyForDescendants} parameter passed to {@link
|
||
android.content.ContentResolver#registerContentObserver
|
||
registerContentObserver()}.
|
||
</dd>
|
||
</dl>
|
||
|
||
<p class="note">
|
||
<strong>Note:</strong> {@code TriggerContentUri()} cannot be used in
|
||
combination with {@link android.app.job.JobInfo.Builder#setPeriodic
|
||
setPeriodic()} or {@link android.app.job.JobInfo.Builder#setPersisted
|
||
setPersisted()}. To continually monitor for content changes, schedule a new
|
||
{@link android.app.job.JobInfo} before the app’s {@link
|
||
android.app.job.JobService} finishes handling the most recent callback.
|
||
</p>
|
||
|
||
<p>
|
||
The following sample code schedules a job to trigger when the system reports
|
||
a change to the content URI, {@code MEDIA_URI}:
|
||
</p>
|
||
|
||
<pre>
|
||
public static final int MY_BACKGROUND_JOB = 0;
|
||
...
|
||
public static void scheduleJob(Context context) {
|
||
JobScheduler js =
|
||
(JobScheduler) context.getSystemService(Context.JOB_SCHEDULER_SERVICE);
|
||
JobInfo.Builder builder = new JobInfo.Builder(
|
||
MY_BACKGROUND_JOB,
|
||
new ComponentName(context, MediaContentJob.class));
|
||
builder.addTriggerContentUri(
|
||
new JobInfo.TriggerContentUri(MEDIA_URI,
|
||
JobInfo.TriggerContentUri.FLAG_NOTIFY_FOR_DESCENDANTS));
|
||
js.schedule(builder.build());
|
||
}
|
||
</pre>
|
||
<p>
|
||
When the system reports a change in the specified content URI(s), your app
|
||
receives a callback and a {@link android.app.job.JobParameters} object is
|
||
passed to the {@link android.app.job.JobService#onStartJob onStartJob()}
|
||
method in {@code MediaContentJob.class}.
|
||
</p>
|
||
|
||
<h3 id="new-jobparam">
|
||
New JobParameter Methods
|
||
</h3>
|
||
|
||
<p>
|
||
The N Developer Preview also extends {@link android.app.job.JobParameters} to
|
||
allow your app to receive useful information about what content authorities
|
||
and URIs triggered the job:
|
||
</p>
|
||
|
||
<dl>
|
||
<dt>
|
||
{@code Uri[] getTriggeredContentUris()}
|
||
</dt>
|
||
|
||
<dd>
|
||
Returns an array of URIs that have triggered the job. This will be {@code
|
||
null} if either no URIs have triggered the job (for example, the job was
|
||
triggered due to a deadline or some other reason), or the number of changed
|
||
URIs is greater than 50.
|
||
</dd>
|
||
|
||
<dt>
|
||
{@code String[] getTriggeredContentAuthorities()}
|
||
</dt>
|
||
|
||
<dd>
|
||
Returns a string array of content authorities that have triggered the job.
|
||
If the returned array is not {@code null}, use {@code getTriggeredContentUris()}
|
||
to retrieve the details of which URIs have changed.
|
||
</dd>
|
||
</dl>
|
||
|
||
<p>
|
||
The following sample code overrides the {@link
|
||
android.app.job.JobService#onStartJob JobService.onStartJob()} method and
|
||
records the content authorities and URIs that have triggered the job:
|
||
</p>
|
||
|
||
<pre>
|
||
@Override
|
||
public boolean onStartJob(JobParameters params) {
|
||
StringBuilder sb = new StringBuilder();
|
||
sb.append("Media content has changed:\n");
|
||
if (params.getTriggeredContentAuthorities() != null) {
|
||
sb.append("Authorities: ");
|
||
boolean first = true;
|
||
for (String auth :
|
||
params.getTriggeredContentAuthorities()) {
|
||
if (first) {
|
||
first = false;
|
||
} else {
|
||
sb.append(", ");
|
||
}
|
||
sb.append(auth);
|
||
}
|
||
if (params.getTriggeredContentUris() != null) {
|
||
for (Uri uri : params.getTriggeredContentUris()) {
|
||
sb.append("\n");
|
||
sb.append(uri);
|
||
}
|
||
}
|
||
} else {
|
||
sb.append("(No content)");
|
||
}
|
||
Log.i(TAG, sb.toString());
|
||
return true;
|
||
}
|
||
</pre>
|
||
|
||
<h2 id="further-optimization">
|
||
Further Optimizing Your App
|
||
</h2>
|
||
|
||
<p>
|
||
Optimizing your apps to run on low-memory devices, or in low-memory
|
||
conditions, can improve performance and user experience. Eliminating the use
|
||
of implicit broadcasts and background services is a great way to make sure
|
||
your app runs well on such devices. Although the N Developer Preview takes
|
||
steps to limit the use of certain implicit broadcasts, consider optimizing
|
||
your app to run without the use of implicit broadcasts and background
|
||
services, entirely.</p>
|
||
|
||
<p>
|
||
To help you test how your app behaves without those background processes, The
|
||
N Developer Preview introduces some additional <a href=
|
||
"{@docRoot}tools/help/adb.html">Android Debug Bridge (ADB)</a> commands:
|
||
</p>
|
||
|
||
<ul>
|
||
<li>To simulate conditions where implicit broadcasts and background services
|
||
are unavailable, enter the following command:
|
||
</li>
|
||
|
||
<li style="list-style: none; display: inline">
|
||
<pre class="no-pretty-print">
|
||
{@code $ adb shell cmd appops set RUN_IN_BACKGROUND ignore}
|
||
</pre>
|
||
</li>
|
||
|
||
<li>To re-enable implicit broadcasts and background services, enter the
|
||
following command:
|
||
</li>
|
||
|
||
<li style="list-style: none; display: inline">
|
||
<pre class="no-pretty-print">
|
||
{@code $ adb shell cmd appops set RUN_IN_BACKGROUND allow}
|
||
</pre>
|
||
</li>
|
||
</ul>
|
||
|
||
<p>
|
||
The Android framework is constantly evolving to help apps run great on a wide
|
||
variety of devices. To learn more and join the discussion, <a href=
|
||
"{@docRoot}">read this blog post!</a>
|
||
</p>
|