page.title=Background Optimizations page.metaDescription=New restrictions to implicit broadcasts. page.keywords="android N", "implicit broadcasts", "job scheduler" page.image=images/cards/card-nyc_2x.jpg @jd:body
Background processes can be memory- and battery-intensive. For example, an implicit broadcast may start many background processes that have registered to listen for it, even if those processes may not do much work. This can have a substantial impact on both device performance and user experience.
To alleviate this issue, Android 7.0 (API level 24) applies the following restrictions:
If your app uses any of these intents, you should remove dependencies on them as soon as possible so that you can target devices running Android 7.0 properly. The Android framework provides several solutions to mitigate the need for these implicit broadcasts. For example, {@link android.app.job.JobScheduler} and {@code GcmNetworkManager} provide robust mechanisms to schedule network operations when specified conditions, such as a connection to an unmetered network, are met. You can now also use {@link android.app.job.JobScheduler} to react to changes to content providers. {@link android.app.job.JobInfo} objects 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}.
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.
Apps targeting Android 7.0 (API level 24) do not receive {@link android.net.ConnectivityManager#CONNECTIVITY_ACTION} broadcasts if they register to receive them in their manifest, and processes that depend on this broadcast will not start. 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.
Note: A {@link android.content.BroadcastReceiver} registered with {@link android.content.Context#registerReceiver Context.registerReceiver()} continues to receive these broadcasts while the app is running.
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 to run when the device connects to an unmetered network and is charging:
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, MyJobService.class)) .setRequiredNetworkType(JobInfo.NETWORK_TYPE_UNMETERED) .setRequiresCharging(true) .build(); js.schedule(job); }
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 JobScheduler sample app.
Applications that use GMSCore services, and target Android 5.0 (API level 21) or lower, can use {@code GcmNetworkManager} and specify {@code Task.NETWORK_STATE_UNMETERED}.
Apps that are running 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 only when specified network conditions are met.
{@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.
The app continues to receive callbacks until either the app exits or it calls {@link android.net.ConnectivityManager#unregisterNetworkCallback unregisterNetworkCallback()}.
In Android 7.0 (API level 24), apps are not able to send or receive {@link android.hardware.Camera#ACTION_NEW_PICTURE} or {@link android.hardware.Camera#ACTION_NEW_VIDEO} broadcasts. This restriction helps alleviate the performance and user experience impacts when several apps must wake up in order to process a new image or video. Android 7.0 (API level 24) extends {@link android.app.job.JobInfo} and {@link android.app.job.JobParameters} to provide an alternative solution.
To trigger jobs on content URI changes, Android 7.0 (API level 24) extends the {@link android.app.job.JobInfo} API with the following methods:
Note: {@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.
The following sample code schedules a job to trigger when the system reports a change to the content URI, {@code MEDIA_URI}:
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(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, JobInfo.TriggerContentUri.FLAG_NOTIFY_FOR_DESCENDANTS)); js.schedule(builder.build()); }
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}.
Android 7.0 (API level 24) also extends {@link android.app.job.JobParameters} to allow your app to receive useful information about what content authorities and URIs triggered the job:
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:
@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; }
Optimizing your apps to run on low-memory devices, or in low-memory conditions, can improve performance and user experience. Removing dependencies on background services and statically-registered implicit broadcast receivers can help your app run better on such devices. Although Android 7.0 (API level 24) takes steps to reduce some of these issues, it is recommended that you optimize your app to run without the use of these background processes entirely.
Android 7.0 (API level 24) introduces some additional Android Debug Bridge (ADB) commands that you can use to test app behavior with those background processes disabled:
{@code $ adb shell cmd appops setRUN_IN_BACKGROUND ignore}
{@code $ adb shell cmd appops setRUN_IN_BACKGROUND allow}