大家在开发应用的时候或多或少都遇到过可感知的界面卡顿现象,尤其是在布局层次嵌套太多,存在不必要的绘制,或者onDraw方法中执行了过多耗时操作、动画执行的次数过多等情况下,很容易造成此类情况。
Android系统每隔16ms就会发送一个VSYNC信号(VSYNC:vertical synchronization 垂直同步,帧同步),触发对UI进行渲染,如果每次渲染都成功,这样就能够达到流畅的画面所需要的正常帧率:60fps。一旦这时候系统正在做大于16ms的耗时操作,系统就会无法响应VSYNC信号,执行渲染工作,导致发生丢帧现象。大家在察觉到APP卡顿的时候,可以看看logcat控制台,会有drop frames
类似的警告
用户容易在UI执行动画、ListView、RecyclerView滑动的时候感知到界面的卡顿与不流畅现象。所以开发者一定要注意在设计布局时不要嵌套太多层,多使用 include
方法引入布局。同时不要让动画执行次数太多,导致CPU或者GPU负载过重。
界面卡顿的主要元凶—— 过度绘制(Overdraw)
过渡绘制是指屏幕上某个像素在同一帧的时间内绘制了多次。在多层次的UI结构里面,如果不可见的UI也在做绘制操作,这就会导致某些像素区域被绘制了多次,这就是很大程度上浪费了CPU和GPU资源。最最常见的过度绘制,就是设置了无用的背景颜色!!!
解决问题的工具和方法
通过Hierarchy Viewer去检测渲染效率,去除不必要的嵌套
通过Show GPU Overdraw去检测Overdraw,最终可以通过移除不必要的背景。
优化实践
1.移除不必要的background
2.使用布局标签优化布局
(1) <include>标签
<include>
的用途就是将布局中的公共部分提取出来以供其他Layout使用,从而实现布局的优化。
(2)<ViewStub>标签
ViewStub
标签同include
一样可以用来引入一个外部布局。不同的是,ViewStub
引入的布局默认是不会显示也不会占用位置的,从而在解析的layout
的时候可以节省cpu、内存等硬件资源。
(3)<merge>标签
merge标签可用于两种典型情况:
- 布局顶接点是
FrameLayout
并且不需要设置background
或者padding
等属性,可使用merge
代替,因为Activity
内容视图的parent view
就是一个FrameLayout
,所以可以用merge
消除只能一个。 - 某布局作为子布局被其他布局include时,使用merge当作该布局的顶节点,这样在被引入时,顶结点会自动被忽略,而其自己点全部合并到主布局中。