• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1page.title=Background Optimizations
2page.metaDescription=New restrictions to implicit broadcasts.
3page.keywords="android N", "implicit broadcasts", "job scheduler"
4page.image=images/cards/card-nyc_2x.jpg
5
6@jd:body
7
8<div id="qv-wrapper">
9  <div id="qv">
10    <h2>
11      In this document
12    </h2>
13
14    <ol>
15      <li>
16        <a href="#connectivity-action">Restrictions on CONNECTIVITY_ACTION</a>
17        <ul>
18          <li>
19            <a href="#sched-jobs">Scheduling Network Jobs on Unmetered
20            Connections</a>
21          </li>
22
23          <li>
24            <a href="#monitor-conn">Monitoring Network Connectivity While the
25            App is Running</a>
26          </li>
27        </ul>
28      </li>
29
30      <li>
31        <a href="#media-broadcasts">Restrictions on NEW_PICTURE and
32        NEW_VIDEO</a>
33        <ul>
34          <li>
35            <a href="#new-jobinfo">New JobInfo methods</a>
36          </li>
37
38          <li>
39            <a href="#new-jobparam">New JobParameter Methods</a>
40          </li>
41        </ul>
42      </li>
43
44      <li>
45        <a href="#further-optimization">Further Optimizing Your App</a>
46      </li>
47    </ol>
48  </div>
49</div>
50
51<p>
52  Background processes can be memory- and battery-intensive. For example, an
53  implicit broadcast may start many background processes that have registered
54  to listen for it, even if those processes may not do much work. This can have
55  a substantial impact on both device performance and user experience.
56</p>
57
58<p>
59  To alleviate this issue, Android 7.0 (API level 24) applies the following
60  restrictions:
61</p>
62
63<ul>
64  <li>Apps targeting Android 7.0 (API level 24) do not receive {@link
65  android.net.ConnectivityManager#CONNECTIVITY_ACTION} broadcasts if they
66  register to receive them in their manifest. Apps that are running can still
67  listen for {@code CONNECTIVITY_CHANGE} on their main thread by registering a
68  {@link android.content.BroadcastReceiver} with {@link
69  android.content.Context#registerReceiver Context.registerReceiver()}.
70  </li>
71
72  <li>Apps cannot send or receive {@link
73  android.hardware.Camera#ACTION_NEW_PICTURE} or {@link
74  android.hardware.Camera#ACTION_NEW_VIDEO} broadcasts. This optimization
75  affects all apps, not only those targeting Android 7.0 (API level 24).
76  </li>
77</ul>
78
79<p>
80  If your app uses any of these intents, you should remove dependencies on them
81  as soon as possible so that you can target devices running Android 7.0
82  properly. The Android framework provides several solutions to mitigate the
83  need for these implicit broadcasts. For example, {@link
84  android.app.job.JobScheduler} and <a href=
85  "https://developers.google.com/android/reference/com/google/android/gms/gcm/GcmNetworkManager">
86  {@code GcmNetworkManager}</a> provide robust mechanisms to schedule network
87  operations when specified conditions, such as a connection to an unmetered
88  network, are met. You can now also use {@link android.app.job.JobScheduler}
89  to react to changes to content providers. {@link android.app.job.JobInfo}
90  objects encapsulate the parameters that {@link android.app.job.JobScheduler}
91  uses to schedule your job. When the conditions of the job are met, the system
92  executes this job on your app's {@link android.app.job.JobService}.
93</p>
94
95<p>
96  In this document, we will learn how to use alternative methods, such as
97  {@link android.app.job.JobScheduler}, to adapt your app to these new
98  restrictions.
99</p>
100
101<h2 id="connectivity-action">
102  Restrictions on CONNECTIVITY_ACTION
103</h2>
104
105<p>
106  Apps targeting Android 7.0 (API level 24) do not receive {@link
107  android.net.ConnectivityManager#CONNECTIVITY_ACTION} broadcasts if they
108  register to receive them in their manifest, and processes that depend on this
109  broadcast will not start. This could pose a problem for apps that want
110  to listen for network changes or perform bulk network activities when the
111  device connects to an unmetered network. Several solutions to get around this
112  restriction already exist in the Android framework, but choosing the right
113  one depends on what you want your app to accomplish.
114</p>
115
116<p class="note">
117  <strong>Note:</strong> A {@link android.content.BroadcastReceiver} registered with
118  {@link android.content.Context#registerReceiver Context.registerReceiver()}
119  continues to receive these broadcasts while the app is running.
120</p>
121
122<h3 id="sched-jobs">
123  Scheduling Network Jobs on Unmetered Connections
124</h3>
125
126<p>
127  When using the {@link android.app.job.JobInfo.Builder JobInfo.Builder} class
128  to build your {@link android.app.job.JobInfo} object, apply the {@link
129  android.app.job.JobInfo.Builder#setRequiredNetworkType
130  setRequiredNetworkType()} method and pass {@link android.app.job.JobInfo
131  JobInfo.NETWORK_TYPE_UNMETERED} as a job parameter. The following code sample
132  schedules a service to run when the device connects to an unmetered
133  network and is charging:
134</p>
135
136<pre>
137public static final int MY_BACKGROUND_JOB = 0;
138...
139public static void scheduleJob(Context context) {
140  JobScheduler js =
141      (JobScheduler) context.getSystemService(Context.JOB_SCHEDULER_SERVICE);
142  JobInfo job = new JobInfo.Builder(
143    MY_BACKGROUND_JOB,
144    new ComponentName(context, MyJobService.class))
145      .setRequiredNetworkType(JobInfo.NETWORK_TYPE_UNMETERED)
146      .setRequiresCharging(true)
147      .build();
148  js.schedule(job);
149}
150</pre>
151
152<p>
153  When the conditions for your job are met, your app receives a callback to run
154  the {@link android.app.job.JobService#onStartJob onStartJob()} method in the
155  specified {@code JobService.class}. To see more examples of {@link
156  android.app.job.JobScheduler} implementation, see the <a href=
157  "{@docRoot}samples/JobScheduler/index.html">JobScheduler sample app</a>.
158</p>
159
160<p>
161  Applications that use GMSCore services, and target Android 5.0 (API level 21)
162  or lower, can use <a href=
163  "https://developers.google.com/android/reference/com/google/android/gms/gcm/GcmNetworkManager">
164  {@code GcmNetworkManager}</a> and specify {@code Task.NETWORK_STATE_UNMETERED}.
165</p>
166
167<h3 id="monitor-conn">
168  Monitoring Network Connectivity While the App is Running
169</h3>
170
171<p>
172  Apps that are running can still listen for {@code CONNECTIVITY_CHANGE} with a
173  registered {@link android.content.BroadcastReceiver}. However, the {@link
174  android.net.ConnectivityManager} API provides a more robust method to request
175  a callback only when specified network conditions are met.
176</p>
177
178<p>
179  {@link android.net.NetworkRequest} objects define the parameters of the
180  network callback in terms of {@link android.net.NetworkCapabilities}. You
181  create {@link android.net.NetworkRequest} objects with the {@link
182  android.net.NetworkRequest.Builder NetworkRequest.Builder} class. {@link
183  android.net.ConnectivityManager#registerNetworkCallback(android.net.NetworkRequest,
184  android.net.ConnectivityManager.NetworkCallback) registerNetworkCallback()}
185  then passes the {@link android.net.NetworkRequest} object to the system. When
186  the network conditions are met, the app receives a callback to execute the
187  {@link android.net.ConnectivityManager.NetworkCallback#onAvailable
188  onAvailable()} method defined in its {@link
189  android.net.ConnectivityManager.NetworkCallback} class.
190</p>
191
192<p>
193  The app continues to receive callbacks until either the app exits or it calls
194  {@link android.net.ConnectivityManager#unregisterNetworkCallback
195  unregisterNetworkCallback()}.
196</p>
197
198<h2 id="media-broadcasts">
199  Restrictions on NEW_PICTURE and NEW_VIDEO
200</h2>
201
202<p>
203  In Android 7.0 (API level 24), apps are not able to send or receive {@link
204  android.hardware.Camera#ACTION_NEW_PICTURE} or {@link
205  android.hardware.Camera#ACTION_NEW_VIDEO} broadcasts. This restriction helps
206  alleviate the performance and user experience impacts when several apps must
207  wake up in order to process a new image or video. Android 7.0 (API level 24)
208  extends {@link android.app.job.JobInfo} and {@link
209  android.app.job.JobParameters} to provide an alternative solution.
210</p>
211
212<h3 id="new-jobinfo">
213  New JobInfo methods
214</h3>
215
216<p>
217  To trigger jobs on content URI changes, Android 7.0 (API level 24) extends
218  the {@link android.app.job.JobInfo} API with the following methods:
219</p>
220
221<dl>
222  <dt>
223    {@code JobInfo.TriggerContentUri()}
224  </dt>
225
226  <dd>
227    Encapsulates parameters required to trigger a job on content URI changes.
228  </dd>
229
230  <dt>
231    {@code JobInfo.Builder.addTriggerContentUri()}
232  </dt>
233
234  <dd>
235    Passes a {@code TriggerContentUri} object to {@link
236    android.app.job.JobInfo}. A {@link android.database.ContentObserver}
237    monitors the encapsulated content URI. If there are multiple {@code
238    TriggerContentUri} objects associated with a job, the system provides a
239    callback even if it reports a change in only one of the content URIs.
240  </dd>
241
242  <dd>
243    Add the {@code TriggerContentUri.FLAG_NOTIFY_FOR_DESCENDANTS} flag to
244    trigger the job if any descendants of the given URI change. This flag
245    corresponds to the {@code notifyForDescendants} parameter passed to {@link
246    android.content.ContentResolver#registerContentObserver
247    registerContentObserver()}.
248  </dd>
249</dl>
250
251<p class="note">
252  <strong>Note:</strong> {@code TriggerContentUri()} cannot be used in
253  combination with {@link android.app.job.JobInfo.Builder#setPeriodic
254  setPeriodic()} or {@link android.app.job.JobInfo.Builder#setPersisted
255  setPersisted()}. To continually monitor for content changes, schedule a new
256  {@link android.app.job.JobInfo} before the app’s {@link
257  android.app.job.JobService} finishes handling the most recent callback.
258</p>
259
260<p>
261  The following sample code schedules a job to trigger when the system reports
262  a change to the content URI, {@code MEDIA_URI}:
263</p>
264
265<pre>
266public static final int MY_BACKGROUND_JOB = 0;
267...
268public static void scheduleJob(Context context) {
269  JobScheduler js =
270          (JobScheduler) context.getSystemService(Context.JOB_SCHEDULER_SERVICE);
271  JobInfo.Builder builder = new JobInfo.Builder(
272          MY_BACKGROUND_JOB,
273          new ComponentName(context, MediaContentJob.class));
274  builder.addTriggerContentUri(
275          new JobInfo.TriggerContentUri(MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
276          JobInfo.TriggerContentUri.FLAG_NOTIFY_FOR_DESCENDANTS));
277  js.schedule(builder.build());
278}
279</pre>
280<p>
281  When the system reports a change in the specified content URI(s), your app
282  receives a callback and a {@link android.app.job.JobParameters} object is
283  passed to the {@link android.app.job.JobService#onStartJob onStartJob()}
284  method in {@code MediaContentJob.class}.
285</p>
286
287<h3 id="new-jobparam">
288  New JobParameter Methods
289</h3>
290
291<p>
292  Android 7.0 (API level 24) also extends {@link android.app.job.JobParameters} to
293  allow your app to receive useful information about what content authorities
294  and URIs triggered the job:
295</p>
296
297<dl>
298  <dt>
299    {@code Uri[] getTriggeredContentUris()}
300  </dt>
301
302  <dd>
303    Returns an array of URIs that have triggered the job. This will be {@code
304    null} if either no URIs have triggered the job (for example, the job was
305    triggered due to a deadline or some other reason), or the number of changed
306    URIs is greater than 50.
307  </dd>
308
309  <dt>
310    {@code String[] getTriggeredContentAuthorities()}
311  </dt>
312
313  <dd>
314    Returns a string array of content authorities that have triggered the job.
315    If the returned array is not {@code null}, use {@code getTriggeredContentUris()}
316    to retrieve the details of which URIs have changed.
317  </dd>
318</dl>
319
320<p>
321  The following sample code overrides the {@link
322  android.app.job.JobService#onStartJob JobService.onStartJob()} method and
323  records the content authorities and URIs that have triggered the job:
324</p>
325
326<pre>
327&#64;Override
328public boolean onStartJob(JobParameters params) {
329  StringBuilder sb = new StringBuilder();
330  sb.append("Media content has changed:\n");
331  if (params.getTriggeredContentAuthorities() != null) {
332      sb.append("Authorities: ");
333      boolean first = true;
334      for (String auth :
335          params.getTriggeredContentAuthorities()) {
336          if (first) {
337              first = false;
338          } else {
339             sb.append(", ");
340          }
341           sb.append(auth);
342      }
343      if (params.getTriggeredContentUris() != null) {
344          for (Uri uri : params.getTriggeredContentUris()) {
345              sb.append("\n");
346              sb.append(uri);
347          }
348      }
349  } else {
350      sb.append("(No content)");
351  }
352  Log.i(TAG, sb.toString());
353  return true;
354}
355</pre>
356
357<h2 id="further-optimization">
358  Further Optimizing Your App
359</h2>
360
361<p>
362  Optimizing your apps to run on low-memory devices, or in low-memory
363  conditions, can improve performance and user experience. Removing
364  dependencies on background services and statically-registered implicit
365  broadcast receivers can help your app run better on such devices. Although
366  Android 7.0 (API level 24) takes steps to reduce some of these issues, it is
367  recommended that you optimize your app to run without the use of these
368  background processes entirely.
369</p>
370
371<p>
372  Android 7.0 (API level 24) introduces some additional <a href=
373  "{@docRoot}tools/help/adb.html">Android Debug Bridge (ADB)</a> commands that
374  you can use to test app behavior with those background processes disabled:
375</p>
376
377<ul>
378  <li>To simulate conditions where implicit broadcasts and background services
379  are unavailable, enter the following command:
380  </li>
381
382  <li style="list-style: none; display: inline">
383<pre class="no-pretty-print">
384{@code $ adb shell cmd appops set <package_name> RUN_IN_BACKGROUND ignore}
385</pre>
386  </li>
387
388  <li>To re-enable implicit broadcasts and background services, enter the
389  following command:
390  </li>
391
392  <li style="list-style: none; display: inline">
393<pre class="no-pretty-print">
394{@code $ adb shell cmd appops set <package_name> RUN_IN_BACKGROUND allow}
395</pre>
396  </li>
397</ul>
398