Android性能优化-App后台优化

   2016-10-17 0
核心提示:原文链接Background Optimizations前言后台进程是内存和电池敏感的。一个隐式的broadcast可能会启动很多监听它的后台进程,即使这些进程可能做得工作不多。这可能丢设备性能和用户体验都有比较大的影响。为了缓解这种问题,7.0(API 24)做了以下限制:Target

原文链接 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 中的 on StartJob() 方法,更多 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) 扩展了 JobInfoJobParameters 来提供一种替代方案。

新的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会收到一个回调和一个传递给 on StartJob() 方法( 在 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.on StartJob() method and records the content authorities and URIs that have triggered the job:

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

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

@Override
publicboolean on StartJob(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

 
反对 0举报 0 评论 0
 

免责声明:本文仅代表作者个人观点,与乐学笔记(本网)无关。其原创性以及文中陈述文字和内容未经本站证实,对本文以及其中全部或者部分内容、文字的真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
    本网站有部分内容均转载自其它媒体,转载目的在于传递更多信息,并不代表本网赞同其观点和对其真实性负责,若因作品内容、知识产权、版权和其他问题,请及时提供相关证明等材料并与我们留言联系,本网站将在规定时间内给予删除等相关处理.

  • Android开发艺术探索学习笔记(三)—Android性能优化之Bitmap导致的内存溢出
    Android开发艺术探索学习笔记(三)—Android性能
    原本计划是按照章节顺序学习《Android开发艺术探索》这本书的,Android性能优化这部分也是本书的最后一章。但是周末的时候,友盟线下反馈的公司项目的一个错误让我不得不提前学习这一块的知识。先看看线下反馈的错误吧:java.lang.OutOfMemoryError:应用程序
  • Android 性能优化之内存泄漏分析工具 LeakCanary
    Android 性能优化之内存泄漏分析工具 LeakCanar
    前言Android内存泄漏的分析与解决是每个Android程序员进阶路上的必备技能。今天就和大家分享一下我的一点点学习心得。开始使用首先在module的build.gradle添加依赖,不同的版本需要添加不同的依赖dependencies {compile fileTree(dir: 'libs', include: ['*.j
  • 携程移动端 UI 界面性能优化实践
    携程移动端 UI 界面性能优化实践
    人类大脑与眼睛对一个画面的连贯性感知其实是有一个界限的,譬如我们看电影会觉得画面很自然连贯,其帧率通常为 24fps;那么,用手机当然也需要感知屏幕操作的连贯性(尤其是动画过渡),所以在手机领域 Android/iOS 索性就把达到这种流畅的帧率规定为 60fps。基
  • Android 性能优化:多线程系列开篇
    Android 性能优化:多线程系列开篇
    前言 Android Performance Patterns Season 5 主要介绍了 Android 多线程环境下的性能问题。通过介绍 Android 提供的多种多线程工具类 (AsyncTask, HandlerThread, IntentService, ThreadPool),让我们熟悉各个组件的适用场景,从而在特定场景下选择性能最好
  • Android应用性能优化系列视图篇——ListView自适应导致的严重性能问题
    Android应用性能优化系列视图篇——ListView自
    ListView是Android中最常用的视图之一,使用的频率仅仅次于三大基础布局,虽然由于使用性和扩展性等原因备受争议,且尽管后来出现了RecyclerView的替代方案,但是ListView仍然广泛地使用在我们的项目中。自从ListView出道至今,已经不知道衍生出了多少问题,
  • Android性能优化-减小APK大小
    Android性能优化-减小APK大小
    原文链接: Reduce APK Size 前言用户通常会避免下载比较大的应用,特别是连接到2G和3G网络,或者按流量收费的设备。这篇文章描述了如何减小apk的大小,帮助你让更多的用户下载你的app。一 理解APK的结构在讨论如何减小apk大小之前,理解apk的结构很有必要。
  • Android性能优化-内存优化
    前言在任何软件开发环境中,RAM都是比较珍贵的资源。在移动操作系统上更是这样,因为它们的物理内存通常受限。尽管在ART和Dalvik虚拟机都会进行垃圾回收的巡航,但这并不意味着你可以忽略何时,何地分配和释放内存。你应该避免内存泄露,通常此后又一些静态成
  • Android性能优化之UI渲染优化
    Android性能优化之UI渲染优化
    原文转自:http://www.cnblogs.com/yezhennan/p/5442031.htmlUI性能测试性能优化都需要有一个目标,UI的性能优化也是一样。你可能会觉得“我的app加载很快”很重要,但我们还需要了解终端用户的期望,是否可以去量化这些期望呢?我们可以从人机交互心理学的角
  • Google官方Android性能优化典范第1季
    Google官方Android性能优化典范第1季
    原文转自:http://www.cnblogs.com/yezhennan/p/5431738.html大多数用户感知到的卡顿等性能问题的最主要根源都是因为渲染性能。从设计师的角度,他们希望App能够有更多的动画,图片等时尚元素来实现流畅的用户体验。但是Android系统很有可能无法及时完成那些
  • Google官方Android性能优化典范第3季
    Google官方Android性能优化典范第3季
    原文转自:http://www.cnblogs.com/yezhennan/p/5443580.html (1)Fun with ArrayMaps 程序内存的管理是否合理高效对应用的性能有着很大的影响,有的时候对容器的使用不当也会导致内存管理效率低下。Android为移动操作系统特意编写了一些更加高效的容器,例如
点击排行