Android性能优化
1. 追求流畅,防止卡顿
卡顿的场景通常是发生在用户交互体验最直接的方面。大概分为四个方面,
如下图所示。
影响卡顿的两大因素,分别是界面绘制和数据处理。
界面绘制
主要原因是绘制的层级深、页面复杂、刷新不合理,由于这些原因导致卡顿的场景更多出现在 UI 和启动后的初始界面以及跳转到页面的绘制上。数据处理
导致这种卡顿场景的原因是数据处理量太大,一般分为三种情况,一是数据在处理 UI 线程,二是数据处理占用 CPU 高,导致主线程拿不到时间片,三是内存增加导致 GC 频繁,从而引起卡顿。
1)布局优化
在Android种系统对View进行测量、布局和绘制时,都是通过对View数的遍历来进行操作的。如果一个View数的高度太高就会严重影响测量、布局和绘制的速度。Google也在其API文档中建议View高度不宜哦过10层。现在版本种Google
使用RelativeLayout替代LineraLayout
作为默认根布局,目的就是降低LineraLayout嵌套产生布局树的高度,从而提高UI渲染的效率。
- 布局复用,使用 <include> 标签重用layout;
- 提高显示速度,使用 <ViewStub> 延迟View加载;
- 减少层级,使用 <merge> 标签替换父级布局;
注意使用wrap_content,会增加measure计算成本;
删除控件中无用属性;
(2)绘制优化
过度绘制是指在屏幕上的某个像素在同一帧的时间内被绘制了多次。
在多层次重叠的 UI 结构中,如果不可见的 UI 也在做绘制的操作,就会导致某些像素区域被绘制了多次,从而浪费了多余的 CPU 以及 GPU 资源。如何
避免过度绘制?
布局上的优化。移除 XML 中非必须的背景,移除 Window 默认的背景、按需显示占位背景图片
自定义View优化。使用canvas.clipRect() 帮助系统识别那些可见的区域,只有在这个区域内才会被绘制。
(3)启动优化
启动优化工具。 应用一般都有闪屏页SplashActivity,优化闪屏页的 UI 布局,可以通过Profile GPU Rendering检测丢帧情况。
(4)刷新优化
- 减少刷新次数,灵活利用缓存及限时刷新;
- 缩小刷新区域,局部刷新,避免多余请求;
(5)动画优化
需要实现动画效果时,需要根据不同场景选择合适的动画框架来实现。有些情况下,可以用硬件加速方式来提供流畅度降低动画卡顿。
2. 追求稳定,防止闪退
一般造成Crash和ANR的都会出现应用崩溃的表现。造成ANR程序无响应的原因主要是在四大组件的耗时操作;而造成Crash的原因却有很多,比如运行时异常的空指针、数组越界、未实例化、强制类型、低内存机制等等,有些时候我们在开发测试阶段都没有出现异常崩溃现象,而发布上线后到了用户手机就会出现各种奇怪闪退。
Android Studio自带的一个内存监视工具,它可以很好地帮助我们进行内存实时分析。通过点击Android Studio右下角的Memory Monitor标签,打开工具可以看见较浅蓝色代表free的内存,而深色的部分代表使用的内存从内存变换的走势图变换,可以判断关于内存的使用状态,例如当内存持续增高时,可能发生内存泄漏;当内存突然减少时,可能发生GC等。
MAT(Memory Analyzer Tool) 是一个快速,功能丰富的 Java Heap 分析工具,通过分析 Java 进程的内存快照 HPROF 分析,从众多的对象中分析,快速计算出在内存中对象占用的大小,查看哪些对象不能被垃圾收集器回收,并可以通过视图直观地查看可能造成这种结果的对象。
小结:影响稳定性的原因很多,比如内存使用不合理、代码异常场景考虑不周全、代码逻辑不合理等,都会对应用的稳定性造成影响。其中最常见的两个场景是:Crash 和 ANR,这两个错误将会使得程序无法使用。所以做好Crash全局监控,处理闪退同时把崩溃信息、异常信息收集记录起来,以便后续分析;合理使用主线程处理业务,不要在主线程中做耗时操作,防止ANR程序无响应发生。
3. 追求续航,防止耗损(耗电优化)
在移动设备中,电池的重要性自然不言而喻,如果手机没电了应用功能技术实现再怎么牛逼,用户也什么都干不成。对于Android操作系统和设备各大开发商来说,对手机耗电的优化从没有停止过,不断地追求更长的待机时间。而对于开发一款应用来说,绝不可以忽略电量耗损的问题,被归为“电池杀手”的应用,最终的结果无疑是走向被用户卸载的道路。比如,有些应用为了保持应用进程长期在后台存活,使用各种不合理进程保活方案,破坏操作系统“生态平衡”,导致用户电量严重耗损,虽然这种流氓开发行为并不违法吧,但是也属于不道德的行为,也同样会被同行所被鄙视的行为。
在 Android5.0 以前,关于应用电量消耗的测试即麻烦又不准确,而5.0 之后Google专门引入了一个获取设备上电量消耗信息的API—— Battery Historian。Battery Historian 是一款由 Google 提供的 Android 系统电量分析工具,直观地展示出手机的电量消耗过程,通过输入电量分析文件,显示消耗情况。
最后提供一些可供参考耗电优化的方法:
(1)计算优化。算法、for循环优化、Switch..case替代if..else、避开浮点运算。
浮点运算:计算机里整数和小数形式就是按普通格式进行存储,例如1024、3.1415926等等,这个没什么特点,但是这样的数精度不高,表达也不够全面,为了能够有一种数的通用表示法,就发明了浮点数。浮点数的表示形式有点像科学计数法(*.*****×10^***),它的表示形式是0.*****×10^***,在计算机中的形式为 .***** e ±***),其中前面的星号代表定点小数,也就是整数部分为0的纯小数,后面的指数部分是定点整数。利用这样的形式就能表示出任意一个整数和小数,例如1024就能表示成0.1024×10^4,也就是 .1024e+004,3.1415926就能表示成0.31415926×10^1,也就是 .31415926e+001,这就是浮点数。浮点数进行的运算就是浮点运算。
浮点运算比常规运算更复杂,因此计算机进行浮点运算速度要比进行常规运算慢得多。
(2)避免Wake Lock使用不当。
Wake Lock是一种锁的机制,主要是相对系统的休眠而言的,,只要有人拿着这个锁,系统就无法进入休眠
意思就是我的程序给CPU加了这个锁那系统就不会休眠了,这样做的目的是为了全力配合我们程序的运行。有的情况如果不这么做就会出现一些问题,比如微信等及时通讯的心跳包会在熄屏不久后停止网络访问等问题。所以微信里面是有大量使用到了Wake_Lock锁。系统为了节省电量,CPU在没有任务忙的时候就会自动进入休眠。有任务需要唤醒CPU高效执行的时候,就会给CPU加Wake_Lock锁。大家经常犯的错误,我们很容易去唤醒CPU来工作,但是很容易忘记释放Wake_Lock。
(3)使用Job Scheduler 管理后台任务。
在Android 5.0 API 21 中,google提供了一个叫做JobScheduler API的组件,来处理当某个时间点或者当满足某个特定的条件时执行一个任务的场景,例如当用户在夜间休息时或设备接通电源适配器连接WiFi启动下载更新的任务。这样可以在减少资源消耗的同时提升应用的效率。
5.追求精简,防止臃肿(安装包瘦身)
其实APK大小对应用使用并没有影响,但应用的安装包越大,用户下载的门槛越高。例如,应用版本的迭代更新,特别是当用户在移动网络情况下,又不得不去下载安装包,才能使用产品满足自身需求。因此,开发应该减小安装包大小,使得让更多用户愿意下载产品和体验产品。
(1)安装包的组成结构
assets文件夹。存放一些配置文件、资源文件,assets不会自动生成对应的 ID,而是通过 AssetManager 类的接口获取。
res。res 是 resource 的缩写,这个目录存放资源文件,会自动生成对应的 ID 并映射到 .R 文件中,访问直接使用资源 ID。
META-INF。保存应用的签名信息,签名信息可以验证 APK 文件的完整性。
AndroidManifest.xml。这个文件用来描述 Android 应用的配置信息,一些组件的注册信息、可使用权限等。
classes.dex。Dalvik 字节码程序,让 Dalvik 虚拟机可执行,一般情况下,Android 应用在打包时通过 Android SDK 中的 dx 工具将 Java 字节码转换为 Dalvik 字节码。
resources.arsc。记录着资源文件和资源 ID 之间的映射关系,用来根据资源 ID 寻找资源。
(2)减少安装包大小
1.代码混淆。使用IDE 自带的 proGuard代码混淆器工具 ,它包括压缩、优化、混淆等功能。
2.资源优化。比如使用Android Lint删除冗余资源,资源文件最少化等。(这个前面已经讲过了)
3.图片优化。比如利用PNG优化工具对图片做压缩处理。如果应用在4.0版本以上,推荐使用 WebP图片格式。
4.可以使用微信开源资源文件混淆工具——AndResGuard。一般可以压缩apk的1M左右大。
5.插件化热修复开发。比如功能模块放在服务器上,按需下载,可以减少安装包大小。
6.避免重复或无用功能的第三方库。例如,百度地图接入基础地图即可、讯飞语音无需接入离线、图片库Glide\Picasso等