一个好的应用,除了在产品的功能和交互吸引人外,在性能上也要有高的要求,另外应用的体验也很重要,如果体验不好,用户用一次之后就很容易会卸载应用,导致用户的流失。因此一个好的应用定义如下:
- 业务/功能
- 符合逻辑的交互
- 优秀的性能
本篇将对性能优化做个着重讲解,因为业务/功能和交互逻辑具体情况具体分析了,我在这边也扯不了。
用户体验的性能问题可以分为四个大类,分别是:
- 流畅
- 稳定
- 省电、省流量
- 安装包小
打造高质量的应用可以分为以上四个方面,快:使用是避免出现卡顿,响应速度快,减少用户等待时间,让用户满意;稳:减少Crash率和ANR率,避免在用户使用过程中出现crash现象。省:节省流量和耗电,减少用户成本,避免用户使用过程中出现手机发烫。小:安装包小可以减少用户安装成本。
要想达到以上四个目标,上图右边的卡顿、内存泄露、崩溃、代码质量和逻辑、安装包过大是我们平时开发过程中出现的比较频繁的问题,如果能解决好这几个问题,我想apk质量会有明显的提升。下面就开始讲解这四大类缺陷的优化方法:
卡顿优化
app卡顿现象是非常影响用户体验的,一旦出现几次卡顿用户就很有可能卸载应用,因此要引起高度的重视,卡顿可以分为UI绘制、应用启动、事件响应;
4种卡顿场景的根本原因可以分为两大类:
- 界面绘制。主要原因是绘制的层级深、页面复杂、刷新不合理,由于这些原因导致卡顿的场景更多出现在 UI 和启动后的初始界面以及跳转到页面的绘制上。
- 数据处理。导致这种卡顿场景的原因是数据处理量太大,一般分为三种情况,一是数据在处理 UI 线程,二是数据处理占用 CPU 高,导致主线程拿不到时间片,三是内存增加导致 GC 频繁,从而引起卡顿。
引起卡顿的原因很多,但不管怎么样的原因和场景,最终都是通过设备屏幕上显示来达到用户,归根到底就是显示有问题,所以,要解决卡顿,就要先了解 Android 系统的显示原理。
Android系统显示原理
Android 显示过程可以简单概括为:Android 应用程序把经过测量、布局、绘制后的 surface 缓存数据,通过 SurfaceFlinger 把数据渲染到显示屏幕上, 通过 Android 的刷新机制来刷新数据。也就是说应用层负责绘制,系统层负责渲染,通过进程间通信把应用层需要绘制的数据传递到系统层服务,系统层服务通过刷新机制把数据更新到屏幕上。
我们都知道在 Android 的每个 View 绘制中有三个核心步骤:Measure、Layout、Draw。具体实现是从 ViewRootImp 类的performTraversals() 方法开始执行,Measure 和 Layout都是通过递归来获取 View 的大小和位置,并且以深度作为优先级,可以看出层级越深、元素越多、耗时也就越长。
真正把需要显示的数据渲染到屏幕上,是通过系统级进程中的 SurfaceFlinger 服务来实现的,那么这个SurfaceFlinger 服务主要做了哪些工作呢?如下:
- 响应客户端事件,创建 Layer 与客户端的 Surface 建立连接。
- 接收客户端数据及属性,修改 Layer 属性,如尺寸、颜色、透明度等。
- 将创建的 Layer 内容刷新到屏幕上。
- 维持 Layer 的序列,并对 Layer 最终输出做出裁剪计算。
既然是两个不同的进程,那么肯定是需要一个跨进程的通信机制来实现数据传递,在 Android 显示系统中,使用了 Android 的匿名共享内存:SharedClient,每一个应用和 SurfaceFlinger 之间都会创建一个SharedClient ,然后在每个 SharedClient 中,最多可以创建 31 个 SharedBufferStack,每个 Surface 都对应一个 SharedBufferStack,也就是一个 Window。
一个 SharedClient 对应一个Android 应用程序,而一个 Android 应用程序可能包含多个窗口,即 Surface 。也就是说 SharedClient 包含的是 SharedBufferStack的集合,其中在显示刷新机制中用到了双缓冲和三重缓冲技术。最