Background optimizations

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, JobScheduler and the new WorkManager 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 JobScheduler to react to changes to content providers. JobInfo objects encapsulate the parameters that JobScheduler uses to schedule your job. When the conditions of the job are met, the system executes this job on your app's JobService.

In this document, we will learn how to use alternative methods, such as JobScheduler, to adapt your app to these new restrictions.

Restrictions on receiving network activity broadcasts

Apps targeting Android 7.0 (API level 24) do not receive 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 BroadcastReceiver registered with Context.registerReceiver() continues to receive these broadcasts while the app is running.

Schedule network jobs on unmetered connections

When using the JobInfo.Builder class to build your JobInfo object, apply the setRequiredNetworkType() method and pass 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(
    new ComponentName(context, MyJobService.class))

When the conditions for your job are met, your app receives a callback to run the onStartJob() method in the specified JobService.class. To see more examples of JobScheduler implementation, see the JobScheduler sample app.

A new alternative to JobScheduler is WorkManager, an API that allows you to schedule background tasks that need guaranteed completion, regardless of whether the app process is around or not. WorkManager chooses the appropriate way to run the work (either directly on a thread in your app process as well as using JobScheduler, FirebaseJobDispatcher, or AlarmManager) based on such factors as the device API level. Additionally, WorkManager does not require Play services and provides several advanced features, such as chaining tasks together or checking a task's status. To learn more, see WorkManager.

Monitor network connectivity while the app is running

Apps that are running can still listen for CONNECTIVITY_CHANGE with a registered BroadcastReceiver. However, the ConnectivityManager API provides a more robust method to request a callback only when specified network conditions are met.

NetworkRequest objects define the parameters of the network callback in terms of NetworkCapabilities. You create NetworkRequest objects with the NetworkRequest.Builder class. registerNetworkCallback() then passes the NetworkRequest object to the system. When the network conditions are met, the app receives a callback to execute the onAvailable() method defined in its ConnectivityManager.NetworkCallback class.

The app continues to receive callbacks until either the app exits or it calls unregisterNetworkCallback().

Restrictions on receiving image and video broadcasts

In Android 7.0 (API level 24), apps are not able to send or receive ACTION_NEW_PICTURE or 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 JobInfo and JobParameters to provide an alternative solution.

Trigger jobs on content URI changes

To trigger jobs on content URI changes, Android 7.0 (API level 24) extends the JobInfo API with the following methods:

Encapsulates parameters required to trigger a job on content URI changes.
Passes a TriggerContentUri object to JobInfo. A ContentObserver monitors the encapsulated content URI. If there are multiple TriggerContentUri objects associated with a job, the system provides a callback even if it reports a change in only one of the content URIs.
Add the TriggerContentUri.FLAG_NOTIFY_FOR_DESCENDANTS flag to trigger the job if any descendants of the given URI change. This flag corresponds to the notifyForDescendants parameter passed to registerContentObserver().

Note: TriggerContentUri() cannot be used in combination with setPeriodic() or setPersisted(). To continually monitor for content changes, schedule a new JobInfo before the app’s 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, 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(
          new ComponentName(context, MediaContentJob.class));
          new JobInfo.TriggerContentUri(MediaStore.Images.Media.EXTERNAL_CONTENT_URI,

When the system reports a change in the specified content URI(s), your app receives a callback and a JobParameters object is passed to the onStartJob() method in MediaContentJob.class.

Determine which content authorities triggered a job

Android 7.0 (API level 24) also extends JobParameters to allow your app to receive useful information about what content authorities and URIs triggered the job:

Uri[] getTriggeredContentUris()
Returns an array of URIs that have triggered the job. This will be 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.
String[] getTriggeredContentAuthorities()
Returns a string array of content authorities that have triggered the job. If the returned array is not null, use getTriggeredContentUris() to retrieve the details of which URIs have changed.

The following sample code overrides the JobService.onStartJob() method and records the content authorities and URIs that have triggered the job:

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(", ");
      if (params.getTriggeredContentUris() != null) {
          for (Uri uri : params.getTriggeredContentUris()) {
  } else {
      sb.append("(No content)");
  Log.i(TAG, sb.toString());
  return true;

Further optimize your app

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 manifest-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:

  • To simulate conditions where implicit broadcasts and background services are unavailable, enter the following command:
  • $ adb shell cmd appops set <package_name> RUN_IN_BACKGROUND ignore
  • To re-enable implicit broadcasts and background services, enter the following command:
  • $ adb shell cmd appops set <package_name> RUN_IN_BACKGROUND allow