原文链接 Background Optimizations

前言

后台进程是内存和电池敏感的。一个隐式的broadcast可能会启动很多监听它的后台进程,即使这些进程可能做得工作不多。这可能丢设备性能和用户体验都有比较大的影响。

为了缓解这种问题,7.0(API 24)做了以下限制:

  • Target为 Android 7.0 (API level 24)的App,将不会再收到在mainfest中注册的 CONNECTIVITY_ACTION广播。运行中的App仍然可以在Main Thread中通过Context.registerReceiver()注册 CONNECTIVITY_CHANGE 广播来监听
  • App 将不能够发送或者接收 ACTION_NEW_PICTURE or ACTION_NEW_VIDEO。这种优化会影响到所有的app,不仅是target为Android7.0的设备。`

因此如果你使用了这些intennt,应该尽快的移除对它们的依赖,以便你的app可以在Target为Android 7.0的设备上正常运行。Android框架提供了几种解决方案去减小对这些隐式广播的依赖。比如,JobScheduler and GcmNetworkManager提供了强健的机制去调度特定情况下的网络操作。比如,你也可以使用JobScheduler去响应content provider的变化。JobInfo对象封装了JobScheduler用于调度job的参数。当满足指定的条件的时候,系统会通JobService过执行该job。

这篇文章将会告诉你如何使用替代的方法,比如JobScheduler去为你的app做这些限制的适配。

一 CONNECTIVITY_ACTION的限制

上面提到,Android 7.0 (API level 24) 将不再能够收到mainfest中注册的 CONNECTIVITY_ACTION 广播。Android框架中已经提供了几种替代方案,如何选择依赖于你的具体实现。

注意:一个通过 Context.registerReceiver()注册的BroadcastReceiver 在app运行期间是可以继续收到广播的。

在不可预测的网络的情况下调度Network Jobs

当使用 JobInfo.Builder 类构建 JobInfo对象的时候, 通过 setRequiredNetworkType() 方法并传递JobInfo.NETWORK_TYPE_UNMETERED参数。下面的示例代码演示了当设备连接到一个未知的网络并且是在充电的时候,去调度一个service去执行的情景:

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);
}

当以上条件满足的时候,app就会收到一个回调去执行指定的JobService.class中的onStartJob()方法,更多 JobScheduler实例可参考 JobScheduler sample app.

使用GMSCore service的应用,并且target是5.0或者以下的,可以使用 GcmNetworkManager 并指定 Task.NETWORK_STATE_UNMETERED。

在APP运行期间监测网络连接

运行期间的App仍然可以监听CONNECTIVITY_CHANGE ,但是, ConnectivityManager 提供了更多强大的方法在特定网络条件满足的时候去触发一个回调。

NetworkRequest对象定义了NetworkCapabilities相关网络回调的参数,你可以通过NetworkRequest.Builder类构建NetworkRequest对象,registerNetworkCallback(),然后将NetworkRequest传递对象到系统中去。当网络条件满足的时候,app就会受到一个回调去执行定义在 ConnectivityManager.NetworkCallback中的 onAvailable()方法。

App会一直接收注册的回调,除非app退出或者调用unregisterNetworkCallback()方法。

二 NEW_PICTURE 和 NEW_VIDEO 的限制

Android 7.0 (API level 24),中,app将不能够发送和接收这两个广播。当几个不同的app必须唤醒设备去处理一个新的Image或者video的时候,这样的限制可以改善性能和用户体验的影响。Android 7.0 (API level 24) 扩展了 JobInfo 和 JobParameters来提供一种替代方案。

新的JobInfo方法

为了让content URI的变化去触发job,Android 7.0 (API level 24)扩展了JobInfo的以下方法:

  • JobInfo.TriggerContentUri()

​ 封装了contentn URL变化需要的参数

  • JobInfo.Builder.addTriggerContentUri()

    传递一个 TriggerContentUri 对象给JobInfo。一个ContentObserver 监测器封装的content URI。如果这里有多个TriggerContentUri 对象关联到某个job上,只要其中某个URI变化,系统都会触发回调事件。

TriggerContentUri.FLAG_NOTIFY_FOR_DESCENDANTS 标志在任何给定URI的子集有变化的时候,都会触发job。该标志对应于传递给registerContentObserver()notifyForDescendants参数。

注意: 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.

注意TriggerContentUri() 不能够和 setPeriodic() 或者 setPersisted()一起使用。为了持续地监测content 的变化,可以在JobService 处理完最近的回调之前去调度一个新的JobInfo。

下面的代码演示了当系统上报一个MEDIA_URI contentURI的时候,调度一个job的场景:

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());
}

当系统上报指定的conent URI(s),你的app会收到一个回调和一个传递给onStartJob()方法( 在MediaContentJob.class中)的 JobParameters 对象。

新的JobParameter方法

Android 7.0 (API level 24)也扩展了JobParameters允许app接收有用的信息,该信息包含了具体是哪些content authorities 和 URIs 触发了job。

  • Uri[] getTriggeredContentUris()

返回一个触发了该Job的URIs数组。如果没有URIs触发job,或者URIs的数量大于50,那么该数组将为null(有可能job是由于其它原因触发,比如一个deadline)。

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

返回一个触发了该Job的content authorities数组。如果返回的数组不为null,可以使用 getTriggeredContentUris()方法获取URIs变化的具体信息。

下面的代码复写了 JobService.onStartJob() 方法,并且记录了触发job的 content authorities 和URIs :

@Override
publicboolean onStartJob(JobParametersparams){
StringBuilder sb =newStringBuilder();
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());
returntrue;
}

三 Further Optimizing Your App

为低内存设备或者在低内存条件做优化,可以提升系能和用户体验。移除对后台的service的依赖和静态方式注册的隐式广播,可以帮助你的app在这样的设备上运行的更好。尽管7.0上采取了一些措施减少了这些问题,但还是建议去优化app,即使在完全没有使用后台进程的情况也可以正常运行。

Android 7.0 (API level 24)引入了一些 Android Debug Bridge (ADB) 命令,可以帮助你测试app在禁止后台进程的情况下app的行为:

  • 模拟隐式广播和后台service不可用的情况,可以使用下面的命令

    $ adb shell cmd appops set RUN_IN_BACKGROUND ignore

  • 重新开启隐式广播和后台service

    $ adb shell cmd appops set RUN_IN_BACKGROUND allow

来源:http://www.lightskystreet.com/2016/10/16/android-optimize-background/

Android性能优化-App后台优化的更多相关文章

  1. Android性能优化-App启动优化

    原文地址:https://developer.android.com/topic/performance/launch-time.html#common 通常用户期望app响应和加载速度越快越好.一个 ...

  2. Android性能优化系列之App启动优化

    Android性能优化系列之布局优化 Android性能优化系列之内存优化 Android性能优化系列之apk瘦身 应用的启动速度缓慢是我们在开发过程中常常会遇到的问题,比方启动缓慢导致的黑屏.白屏问 ...

  3. Android性能优化系列---管理你的app内存

     文章出处:http://developer.android.com/training/articles/memory.html#YourApp Random-access memory(RAM)在任 ...

  4. android app性能优化大汇总(google官方Android性能优化典范 - 第2季)

    Google前几天刚发布了Android性能优化典范第2季的课程,一共20个短视频,包括的内容大致有:电量优化,网络优化,Wear上如何做优化,使用对象池来提高效率,LRU Cache,Bitmap的 ...

  5. 【腾讯Bugly干货分享】Android性能优化典范——第6季

    本文来自于腾讯bugly开发者社区,非经作者同意,请勿转载,原文地址:http://dev.qq.com/topic/580d91208d80e49771f0a07c 导语 这里是Android性能优 ...

  6. Android性能优化典范第一季

    2015年伊始,Google发布了关于Android性能优化典范的专题,一共16个短视频,每个3-5分钟,帮助开发者创建更快更优秀的Android App.课程专题不仅仅介绍了Android系统中有关 ...

  7. [转]Android性能优化典范

    2015年伊始,Google发布了关于Android性能优化典范的专题,一共16个短视频,每个3-5分钟,帮助开发者创建更快更优秀的Android App.课程专题不仅仅介绍了Android系统中有关 ...

  8. [Android Pro] Android性能优化典范第一季

    reference to : http://www.cnblogs.com/hanyonglu/p/4244035.html#undefined 2015年伊始,Google发布了关于Android性 ...

  9. Android性能优化(一)

    Android性能优化典范 1.大多数用户感知到的卡顿等性能问题的最主要根源都是因为渲染性能. 从设计师的角度,他们希望App能够有更多的动画,图片等时尚元素来实现流畅的用户体验. 但是Android ...

随机推荐

  1. hdu3193 降维+rmq

    /* 给定n个数对(p,d),如果有这么一个数对(pi,di),其他所有的数对都不能严格小于这个数对 请求出有多少个这样的数对! 解法:对于数对(p,d),能找到在[1,p-1]之间的小于d的数对,那 ...

  2. 性能测试四十:Mysql存储过程造数据

    性能测试是基于大量数据的,而进行性能测试之前肯定没那么多数据,所以就要自己准备数据 数据构造方法: 1.业务接口 -- 适合数据表关系复杂 -- 优点:数据完整性比较好2.存储过程 -- 适合表数量少 ...

  3. STM32的HAL库中的DMA_FLAG_TCIF3_7等几个宏定义的含义

    DMA_FLAG_TCIF0_4就是指DMA的通道0和通道4,DMA_FLAG_TCIF1_5就是指DMA的通道1和通道5,DMA_FLAG_TCIF2_6就是指DMA的通道2和通道6,DMA_FLA ...

  4. 安装oracle11g时遇到INS-13001环境不满足最低要求

    在安装oracle11g,点击setup.exe之后,弹出了如下提示框: 解决方法: 首先,打开你解压后的database文件夹,找到stage,然后cvu,找到cvu_prereq.xml文件,用记 ...

  5. springboot2.0+dubbo整合分布式服务发布和调用

    最近项目上要对以前的老项目做分布式的整改,因此我专门花了点时间研究下当前比较热门的dubbo和springboot结合使用,以前使用过dubbo,但是没有与springboot结合过,在网上查了点资料 ...

  6. 090实战 Hadoop离线项目介绍(不包括程序)

    一:项目场景 1.需求分析 根据用户行为数据进行程序的处理,得到结果保存到关系型数据库中 需要收集用户(系统使用者)在不同客户端上产生的用户行为数据,最终保存到hdfs上 需要明确收集字段的相关信息, ...

  7. Cpu 常见系列以及型号

    Intel旗下 赛扬(Celeron)——桌面低端 奔腾(Pentium)—— 桌面中端 酷睿 (Core)——桌面高端 至强(Xeon)——服务器中端 安腾(Itanium)——服务器高端 凌动(A ...

  8. POJ 3903 Stock Exchange 【最长上升子序列】模板题

    <题目链接> 题目大意: 裸的DP最长上升子序列,给你一段序列,求其最长上升子序列的长度,n^2的dp朴素算法过不了,这里用的是nlogn的算法,用了二分查找. O(nlogn)算法 #i ...

  9. 前端解读面向切面编程(AOP)

    前言 面向对象(OOP)作为经典的设计范式,对于我们来说可谓无人不知,还记得我们入行起始时那句经典的总结吗-万事万物皆对象. 是的,基于OOP思想封装.继承.多态的特点,我们会自然而然的遵循模块化.组 ...

  10. SQL server学习(四)T-SQL编程之事务、索引和视图

    今天来分享下T-SQL高级编程中的事务.索引.视图,可以和之前的SQL server系列文章结合起来. 一.事务 事务(TRANSACTION)是作为单个逻辑工作单元执行的一系列操作,这些操作作为一个 ...