Home | History | Annotate | Download | only in performance
      1 page.title=Background Optimizations
      2 page.metaDescription=New restrictions to implicit broadcasts.
      3 page.keywords="android N", "implicit broadcasts", "job scheduler"
      4 page.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>
    137 public static final int MY_BACKGROUND_JOB = 0;
    138 ...
    139 public 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 apps {@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>
    266 public static final int MY_BACKGROUND_JOB = 0;
    267 ...
    268 public 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
    328 public 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