简介
Android性能方面的技术是重中之重,一个性能优越的App给用户有个良好体验,如果应用使用起来很不稳定,出现崩溃、网络错误或者网络超时、响应速度慢、列表滚动卡顿、流量大、耗电等问题,可能会引起用户卸载的后果。
Android性能优化主要有四个方面:
1、流畅(卡顿)
2、稳定(内存溢出、崩溃)
3、耗损(耗电、流量、网络)
4、安装包(APK瘦身)
1、什么是卡顿
卡顿是人的一种视觉感受,比如我们滑动界面时,如果滑动不流畅就会有卡顿的感觉,这种感觉需要有一个量化指标。
FPS(帧率),每秒显示帧数。表示图形处理器每秒能够更新的次数。高的帧率可以得到更流畅、更逼真的动画。一般来说12fps大概类似手动快速翻动书籍的帧率,这明显感知到不够顺滑。30fps就是可以接受的,但是无法顺畅表现绚丽的画面内容。提升至60fps则可以明显提升交互感和逼真感,但是一般来说超过75fps就不容易察觉到有明显的流畅度提升了,如果是VR设备需要高于75fps,才可能消除眩晕的感觉。
开发App的性能目标就是保持60fps,这意味着每一帧你只有16ms约等于1000/60的时间来处理所有任务。Android系统每隔发出VSYNC信号,触发对UI进行渲染,如果每次渲染都成功,这样就能够达到流畅的画面所需要的60fps。
渲染机制
- CPU: 中央处理器,它集成了运算,缓冲,控制等单元,包括绘图功能.CPU将对象处理为多维图形,纹理(Bitmaps、Drawables等都是一起打包到统一的纹理).
- GPU:一个类似于CPU的专门用来处理Graphics的处理器, 作用用来帮助加快栅格化操作,当然,也有相应的缓存数据(例如缓存已经光栅化过的bitmap等)机制。
- OpenGL ES是手持嵌入式设备的3DAPI,跨平台的、功能完善的2D和3D图形应用程序接口API,有一套固定渲染管线流程. 附相关OpenGL渲染流程资料
- DisplayList 在Android把XML布局文件转换成GPU能够识别并绘制的对象。这个操作是在DisplayList的帮助下完成的。DisplayList持有所有将要交给GPU绘制到屏幕上的数据信息。
- 栅格化 是 将图片等矢量资源,转化为一格格像素点的像素图,显示到屏幕上,过程图如下.
栅格化操作
- 垂直同步VSYNC:让显卡的运算和显示器刷新率一致以稳定输出的画面质量。它告知GPU在载入新帧之前,要等待屏幕绘制完成前一帧。下面的三张图分别是GPU和硬件同步所发生的情况,Refresh Rate:屏幕一秒内刷新屏幕的次数,由硬件决定,例如60Hz.而Frame Rate:GPU一秒绘制操作的帧数,单位是30fps,正常情况过程图如下.
正常情况
2.渲染机制分析
渲染流程线
UI对象---->CPU处理为多维图形,纹理 -----通过OpeGL ES接口调用GPU----> GPU对图进行光栅化(Frame Rate ) ---->硬件时钟(Refresh Rate)----垂直同步---->投射到屏幕
图片名称
正常情况
渲染超时,计算渲染时间超过16ms
当这一帧画面渲染时间超过16ms的时候,垂直同步机制会让显示器硬件 等待GPU完成栅格化渲染操作,
这样会让这一帧画面,多停留了16ms,甚至更多.这样就这造成了 用户看起来 画面停顿.
当GPU渲染速度过慢,就会导致如下情况,某些帧显示的画面内容就会与上一帧的画面相同
GPU超时情况
丢帧情况 | 卡顿情况 |
0-10帧 | 流畅 |
10-20帧 | 较卡 |
20-40帧 | 很卡 |
40-60帧 | 卡死了 |
3、渲染优化
1.1、GPU过度绘制简介
什么是过度绘制,过度绘制就是屏幕上某个像素点在一帧中被重复绘制多次。
GPU绘制的过程,就跟刷墙一样,一层一层的进行,16ms刷一次。这样会引起相同背景图层重复绘制的现象,造成绘制效率下降,如果图层重复的区域只绘制一次,这样就减少资源不必要的浪费。
1.2、可以使用手机开发者设置中的过度绘制查看工具
手机端的开发者选项里,有调试GPU过度绘制工具选项,如下图:
点击上图调试GPU过度绘制工具,弹出弹窗,然后点击弹窗中的打开显示过度绘制区域,手机就可以查看当前view的组件图层颜色了,其中颜色代表渲染的图层情况,分别代表1层、2层、3层、4层覆盖。
依据过度绘制的层度可以分成:
1、无过度绘制(一个像素只被绘制了一次)
2、过度绘制x1(一个像素被绘制了两次)
3、过度绘制x2(一个像素被绘制了三次)
4、过度绘制x3(一个像素被绘制了四次)
5、过度绘制x4+(一个像素被绘制了五次以上)
颜色与过度绘制:
1、view显示原色:没有过度绘制
2、view显示蓝色:1次过度绘制
3、view显示绿色:2次过度绘制
4、view显示粉色:3次过度绘制
5、view显示红色:4次及以上过度绘制
1.3、优化过度绘制
1、去除Activity自带的默认背景颜色
查看Android源码里的Theme主题,如下:
<style name="Theme">
...
<!-- Window attributes -->
<item name="windowBackground">@drawable/screen_background_selector_dark</item>
...
</style>
去掉系统默认的背景可以做如下修改:
<style name="AppTheme" parent="android:Theme.Light.NoTitleBar"> <item name="android:windowBackground">@null</item> </style>
或者在Activity的onCreate方法中调用如下代码:
getWindow().setBackgroundDrawable(null);
2、使用Canvas的clipRect和clipPath方法限制View的绘制区域
3、ImageView的background和imageDrawable重叠
Android中所有的View都可以设置background。但是ImageView设置背景可以有两种设置方式,分别是background和imageDrawable,如果在一个ImageView都使用了两种方式设置同一张图片,或者backgroud设置了颜色值还设置ImageDrawable图片,这样就出现两层绘制,导致过度绘制。
4、内存优化
1.1、监测页面的内存使用情况,可以查看内存的抖动图,然后追踪到代码的某个函数中的某行代码,看看那行代码的某对象分配的内存大小,分配过大时,可以根据最优实现的方式修改优化,如下图:
先检查出现内存抖动的区域,然后重新在内存抖动之前点击Record按钮开始录制内存分配信息,过一会在点击停止录制。
找到分配的内存多大的函数或者代码,如图:
点击Jump to Source就会跳到指定类下的指定的代码
点击Visualization可以查看代码执行过程中的函数,并且可以查看分配的内存大小