一般App主要的性能问题如下:
- APP启动慢
- 界面跳转慢
- 事件相应慢
- 滑动和动画卡顿
- 展现内容慢
优化核心
- GPU过渡绘制的优化
- 不需要显示的布局及时隐藏
- 去掉层叠布局中多余的背景设置
- 图片控件有前景内容的时候不显示背景
- 界面背景定义到Activity的主题中
- 减少Drawable的复杂Shape使用
- 自定义控件onDraw函数减少绘制层次
- 自定义控件使用canvas.clipRect
- 优化布局性能
- 优化层级
- 灵活使用布局
- 减少View数量
- 异步infalte或者提前infalte
- 自己做控件的回收复用
- 加快界面显示
- 主线程不做耗时操作
- 减少主线程GC停顿
- 利用本地缓存
- 减少数据传输和解析时间
- 注意线程优先级
- 利用局部刷新
主要的优化工具如下
- GPU Profile:查看每一帧的绘制情况。除了查看帧率,我还会用这个工具检查各个界面在静默状态下的不必要的刷新问题。
- Show GPU Overdraw:查看过渡绘制用的工具,因为手淘的很多界面效果也比较复杂,很容易出现过渡绘制。
- Dump View Hierarchy:用于查看界面的布局、View和层级嵌套情况。特别是在没有源代码的情况下,查看非常方便。
- TraceView:强大的性能跟踪工具,也是我们在优化中用的最多的工具。
- SysTrace:主要用于查看UI的绘制问题,跟踪CPU执行情况等。
- Trace OpenGL:可以录制每一帧的绘制过程,逐个绘制命令查看。
- AlloCation Tracker:内存分配跟踪,也是个调试性能的强大工具。
- Threads 工具可以显示所有线程信息及查看线程正在执行的代码。
- Heap和Memory Monitor:查看内存的分配和变化情况。Memory Monitor还可以查看内存的抖动和GC情况。
优化过程中的一些经验
写SharedPreferences的apply函数需要注意,因为Commit函数会阻塞IO,这个函数虽然执行很快,但是系统会有另外一个线程来负责写操作,当apply频率高的时候,该线程就会比较占用CPU资源。类似的还有统计埋点等,在主线程埋点但异步线程提交,频率高的情况也会出现这样的问题。优化过程就是删除不必要的io操作,有些做延后处理。例如统计数据,淘宝减少了采样的频率,并且增加缓存数量,以空间换时间,减少数据库和SharedPreference的读写。在做较多数据库操作的时候也会开启事务功能来减少IO的次数。
其次查看布局性能,一种是直接查看,如onMeasure,OnLayout函数占用的百分比和平均执行时间过高导致的性能问题,很直观就可以看出来。还有就是例如getview中的布局性能,整体的查看inflate的个数和耗时问题的跟踪。还有一种是通过View的draw函数或者buildeDisplayList函数的调用和递归调用次数来判断布局的复杂度。
关于复用问题,比如在listview滑动过一遍后,在对这部分区域做跟踪,如果getview中还有infalte布局,那就是复用还有可以优化的地方。
类的初始化耗时,像构造函数,静态初始化等这些问题很容易忽视,但是在性能优化的后期,这些小的细节点,也是优化的方向,特别是在主线程中调用的时候。
以前在启动阶段会安装主要模块的bundle,首页再启动后过3秒也会发送通知来唤起更多的模块,像淘宝的webview框架,在初始化的时候会把线上活动资源都缓存到本地,这个过程设计到json的解析,下载和解压缩等,非常耗资源等等,这些模块叠加在一起就导致了首页就会直接卡主及白屏很长一段时间,所以对这一种模块改为懒加载,并且要限制拉取活动的数量。还有像购物车,微淘,店铺,旺信等以前是首次启动会安装,也是改为懒加载。因为首次Dexopt会比较费时,特别是安卓5.0以后,所以很多模块都改为懒加载,这样首次使用该模块的时候变慢一点,但是整体启动速度一下就提升了。
首页在欢迎页的时候开始初始化布局等,加快展示。退出的时候以前都是销毁Activity的,为了加快下次启动,释放到图片等主要资源,Activity不做销毁。
总结
发现性能问题的时候首先要分析原因,是卡住还是卡顿,是网络慢的问题,还是是内存问题亦或是其他系统的问题。手淘遇到有时候手机厂商的一些特殊控件的bug也会导致问题。安卓系统本身的内存管理和一些监控软件有时候也会导致性能问题。
通过多种工具额配合找出问题。
有些问题,一个地方存在很可能其他地方也有,可以到类似的模块去查看,如圆形的图案,输入控件在输入法退出时引发的自动刷新问题。
建立程序内的监控,以及代码层面的扫描等,添加性能监控的模块可以实时监控和统计程序中的性能问题。