Android APP 性能优化
目前市场上各种APP都存在各种各样的性能问题,有些甚至在用户使用过程中突然奔溃,或者每次更新花费大量的流量,这样就给用户带来了很不好的用户体验。可以把用户体验的性能问题主要总结为4个类别:流畅、 稳定 、省电、省流量、安装包小。
流畅:流畅的操作体验。使用时避免出现卡顿,响应速度快,减少用户等待的时间,满足用户期望。
稳定:减低 crash 率和 ANR 率,不要在用户使用过程中崩溃和无响应。
省:节省流量和耗电,减少用户使用成本,避免使用时导致手机发烫。
小:安装包小可以降低用户的安装成本。
流畅
Android 应用启动慢,使用时经常卡顿,是非常影响用户体验的,应该尽量避免出现。卡顿的场景有很多,按场景可以分为4类:UI 绘制、应用启动、页面跳转、事件响应。UI:包括UI绘制和刷新;应用启动包括:冷启动、热启动、安装启动;跳转:页面切换和前后台切换;响应:按键、系统事件、滑动。这4种卡顿场景的根本原因可以分为两大类: 界面绘制:主要原因是绘制的层级深、页面复杂、刷新不合理,由于这些原因导致卡顿的场景更多出现在 UI 和启动后的初始界面以及跳转到页面的绘制上。 数据处理:导致这种卡顿场景的原因是数据处理量太大,一般分为三种情况,一是数据在处理 UI 线程,二是数据处理占用 CPU 高,导致主线程拿不到时间片,三是内存增加导致 GC 频繁,从而引起卡顿 。引起卡顿的原因很多,但不管怎么样的原因和场景,最终都是通过设备屏幕上显示来达到用户,归根到底就是显示有问题,所以,要解决卡顿,就要先了解 Android 系统的显示原理具体参考Android屏幕刷新机制。
性能分析工具
性能问题并不容易复现,也不好定位,但是真的碰到问题还是需要去解决的,那么分析问题和确认问题是否解决,就需要借助相应的的调试工具,比如查看 Layout 层次的 Hierarchy View、Android 系统上带的 GPU Profile 工具和静态代码检查工具 Lint 等,这些工具对性能优化起到非常重要的作用,所以要熟悉,知道在什么场景用什么工具来分析。
1、Profile GPU Rendering
它的功能特点如下:一个图形监测工具,能实时反应当前绘制的耗时
横轴表示时间,纵轴表示每一帧的耗时。
随着时间推移,从左到右的刷新呈现。
提供一个标准的耗时,如果高于标准耗时,就表示当前这一帧丢失。
2、TraceView TraceView 是 Android SDK 自带的工具,用来分析函数调用过程,可以对 Android 的应用程序以及 Framework 层的代码进行性能分析。它是一个图形化的工具,最终会产生一个图表,用于对性能分析进行说明,可以分析到每一个方法的执行时间,其中可以统计出该方法调用次数和递归次数,实际时长等参数维度,使用非常直观,分析性能非常方便。
TraceView文件traceView界面比较复杂,其UI划分为上下两个面板,上面为TimeLine(时间线面板),下面为Profile Panel (分析面板)。
时间线面板又分为左右两个pane:
● 左边 Pane 显示的是测试数据中所采集的线程信息。由图可知,本次测试数据采集了 main 线程,传感器线程和其它系统辅助线程的信息。
● 右边 Pane 所示为时间线,时间线上是每个线程测试时间段内所涉及的函数调用信息。这些信息包括函数名、函数执行时间等。由图可知,main 线程对应行的内容非常丰富,而其他线程在这段时间内干得工作则要少得多。
另外,开发者可以在时间线 Pane 中移动时间线纵轴。纵轴上边将显示当前时间点中某线程正在执行的函数信息。
下半部分,Profile Panel (分析面板)为traceView的核心界面,主要展示了某个线程中各个函数调用的情况,包括CPU使用时间,调用次数等。而这些信息正是查找 hotspot 的关键依据,所以对于开发者来说一定要了解Profile Panel中各列的含义。
我们一般关注这两条就可以了:
● 一类是调用次数不多,但每次调用却需要花费很长时间的函数。
● 一类是那些自身占用时间不长,但调用却非常频繁的函数。
3、Systrace UI 性能分析 Systrace 是 Android 4.1及以上版本提供的性能数据采样和分析工具,它是通过系统的角度来返回一些信息。它可以帮助开发者收集 Android 关键子系统,如 surfaceflinger、WindowManagerService 等 Framework 部分关键模块、服务、View系统等运行信息,从而帮助开发者更直观地分析系统瓶颈,改进性能。Systrace 的功能包括跟踪系统的 I/O 操作、内核工作队列、CPU 负载等,在 UI 显示性能分析上提供很好的数据,特别是在动画播放不流畅、渲染卡等问题上。
我们主要查看界面上的Alert、Frames,其中可以用绿色、黄色、红色来区分当前界面的性能等级分别是优、良、差。当遇到红色的时候肯定当前的性能需要优化。当我们点击了Alerts或者点击右边的Alerts列表中的任何一点我们可以看到在界面的最底部会相对应的优化提示以及可能会出现优化的视频教程链接。
提示说View的draw绘制花的时间太长了,然后我们可以根据Description来很明白的看到提示的内容是什么。然后我们可以点击一块Frames中的F来查看,同样的它会生成一份跟Alerts类似的报告结果并放在界面的最低端。我们可以通过按下m键查看这一帧到下一帧所花费的时间以及哪个方法被调用的最长
可以明显看到这时间>16.6ms,系统要求UI的60fps水准所以系统会报出黄色的警告。照样我们从Description中可以读出到底是哪里出了问题。当然Systrace无法帮你定位到代码里面的具体到某一行代码,但是我们可以通过Alerts和Frames来能基本上优化了不足的地方,然后我们可以根据TraceView来分析具体函数花了多长时间来进一步优化代码提高性能。
优化建议
1、布局优化
布局是否合理主要影响的是页面测量时间的多少,我们知道一个页面的显示测量和绘制过程都是通过递归来完成的,多叉树遍历的时间与树的高度h有关,其时间复杂度 O(h),如果层级太深,每增加一层则会增加更多的页面显示时间,所以布局的合理性就显得很重要。那布局优化有哪些方法呢,主要通过减少层级、减少测量和绘制时间、提高复用性三个方面入手。总结如下:
减少层级:合理使用 RelativeLayout 和 LinerLayout,合理使用Merge。
提高显示速度:使用 ViewStub,它是一个看不见的、不占布局位置、占用资源非常小的视图对象。
布局复用:可以通过标签来提高复用。
尽可能少用wrap_content。wrap_content 会增加布局 measure 时计算成本,在已知宽高为固定值时,不用wrap_content 。
删除控件中无用的属性。
2、避免过度绘制
过度绘制是指在屏幕上的某个像素在同一帧的时间内被绘制了多次。在多层次重叠的 UI 结构中,如果不可见的 UI 也在做绘制的操作,就会导致某些像素区域被绘制了多次,从而浪费了多余的 CPU 以及 GPU 资源。如何避免过度绘制呢,如下:
布局上的优化。移除 XML 中非必须的背景,移除 Window 默认的背景、按需显示占位背景图片
自定义View优化。使用 canvas.clipRect()来帮助系统识别那些可见的区域,只有在这个区域内才会被绘制。
3、启动优化
通过对启动速度的监控,发现影响启动速度的问题所在,优化启动逻辑,提高应用的启动速度。启动主要完成三件事:UI 布局、绘制和数据准备。因此启动速度优化就是需要优化这三个过程:
UI 布局。应用一般都有闪屏页,优化闪屏页的 UI 布局,可以通过 Profile GPU Rendering 检测丢帧情况。
启动加载逻辑优化。可以采用分布加载、异步加载、延期加载策略来提高应用启动速度。
数据准备。数据初始化分析,加载数据可以考虑用线程初始化等策略。
4、合理的刷新机制
在应用开发过程中,因为数据的变化,需要刷新页面来展示新的数据,但频繁刷新会增加资源开销,并且可能导致卡顿发生,因此,需要一个合理的刷新机制来提高整体的 UI 流畅度。合理的刷新需要注意以下几点:
减少刷新次数。
尽量避免后台有高的 CPU 线程运行。
缩小刷新区域。
5、其他
在实现动画效果时,需要根据不同场景选择合适的动画框架来实现。有些情况下,可以用硬件加速方式来提供流畅度。