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@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