知识体系十二:UI卡顿优化
CPU准备数据,通过Driver层把数据交给CPU渲染,其中CPU主要负责Measure、Layout、Record、Execute的数据计算工作,GPU负责Rasterization(栅格化)、渲染。因为图形API不允许CPU直接和GPU通信,所以要通过一个图形驱动的中间层来进行连接,在图形驱动里面维护了一个队列,CPU把display list(待显示的数据列表)添加到队列中,GPU从这个队列中取出数据进行绘制,最终才在显示屏上显示出来。
双缓冲的含义?
双缓冲意味着要使用两个缓冲区(在上文提及的SharedBufferStack中),其中一个称为Front Buffer,另一个称为Back Buffer。UI总是先在Back Buffer中绘制,然后再和Front Buffer交换,渲染到显示设备中。即只有当另一个buffer的数据准备好后,才会通过io_ctl系统调用来通知显示设备切换Buffer。
1.CPU方面问题:
CPU主要的问题是无用布局标签的宽高测量(onMeasure)、位置排版(onLayout)。如果这两个过程时间过长16ms内不能提交给GPU渲染就会导致下一帧画面显示不了,导致卡顿。
CPU 优化建议:
(1).没有用的父布局时指没有背景绘制或者没有大小限制的父布局,这样的布局不会对UI效果产生任何影响。我们可以把没有用的父布局,通过<merge/>标签合并来减少UI的层次
(2).使用线性布局LinearLayout排版导致UI层次变深,如果有这类问题,我们就使用相对布局RelativeLayout代替LinearLayout,减少UI的层次(3).不常用的UI被设置成GONE,比如异常的错误页面,如果有这类问题,我们需要用<ViewStub/>标签,代替GONE提高UI性能
2.常用的优化示例
(1). include 标签
include标签常用于将布局中的公共部分提取出来供其他layout共用,以实现布局模块化,这在布局编写方便提供了大大的便利。
(2). viewstub 标签
viewstub标签同include标签一样可以用来引入一个外部布局,不同的是,viewstub引入的布局默认不会扩张,即既不会占用显示也不会占用位置,从而在解析layout时节省cpu和内存。
viewstub常用来引入那些默认不会显示,只在特殊情况下显示的布局,如进度布局、网络失败显示的刷新布局、信息出错出现的提示布局等。
(3). merge 标签
在使用了include后可能导致布局嵌套过多,多余不必要的layout节点,从而导致解析变慢
merge标签可用于两种典型情况:
(1). 布局顶结点是FrameLayout且不需要设置background或padding等属性,可以用merge代替,因为Activity内容试图的parent view就是个FrameLayout,所以可以用merge消除只剩一个。
(2). 某布局作为子布局被其他布局include时,使用merge当作该布局的顶节点,这样在被引入时顶结点会自动被忽略,而将其子节点全部合并到主布局中。
2.GPU方面:
GPU主要影响绘制(onDraw),最常见的问题是我们所说的过度绘制(overdraw),通常是在像素着色过程中,通过其他工具进行后期着色时浪费了GPU处理时间。
过度绘制描述的是屏幕上的某个像素在同一帧的时间内被绘制了多次。在多层次重叠的UI结构里面,如果不可见的UI也在做绘制的操作,会导致某些像素区域被绘制了多次。这样就会浪费大量的CPU以及GPU资源。
当设计上追求更华丽的视觉效果的时候,我们就容易陷入采用复杂的多层次重叠视图来实现这种视觉效果的怪圈。这很容易导致大量的性能问题,为了获得最佳的性能,我们必须尽量减少Overdraw的情况发生。
幸运的是,我们可以通过手机设置里面的开发者选项,打开Show GPU Overdraw的选项,观察UI上的Overdraw情况。
GPU 优化建议:
1.在开发中很多比较复杂的自定义View。
对于自定义View矩形区域重叠的,我们可以把无用区域即被覆盖的区域给剪切掉使用 clipRect() api。这样系统就不会处理这部分区域的数据,即而节约了CPU的计算、GPU的渲染时间,不影响下一帧的绘制。
2.多个布局嵌套导致的布局重叠,移除XML布局文件中非必需的Background
其他方面影响卡顿:
1.内存抖动
内存抖动就是段时间内大量创建/销毁对象,比如在for循环、动画中等创建对象。
导致UI卡顿:段时间内创建/销毁对象就会出发GC线程开始检测垃圾回收,由于GC线程具有 stop all world 特性,所以gc处罚后就会暂停我们的主(main ui)线程,所以我们的某一时刻的ui就得不到绘制,界面就会断断续续的卡顿。
2.减少调用会出发requestlayout()的方法比如setLayoutparams(),因为每调一次该方法视图就要重新计算一次,阻碍了view的绘制。
3.对于列表view 可用 滚动不加载 image、分页加载、可用缩略图、使用lru缓存。
性能分析工具
Android常用的绘制优化工具一般有如下几种:
Hierarchy View:查看Layout层次
Android Studio自带的Profile CPU工具
静态代码检查工具Lint
Profile GPU Rendering 手机自带的检测工具:
蓝色:表示测量绘制的时间,需要多长时间去创建和更新DisplayList。在蓝色的线很高时,有可能是因为需要重新绘制,或者自定义视图的onDraw函数处理事情太多。
红色:表示Android进行2D渲染Display List的执行的时间。当红色的线非常高时,可能是由于重新提交了视图导致的。
橙色:处理时间或CPU告诉GPU渲染一帧的地方,如果柱状图很高,就意味着GPU太繁忙了。
紫色:将资源转移到渲染线程的时间。
TraceView
Systrace
UI优化有两个方面:1.ui卡顿方向、2.ui适配方向
https://juejin.cn/post/7050404740760354829