性能优化(三):布局优化

627 阅读3分钟

一.绘制原理

1.CPU负责计算显示内容(测量,位置,绘制等);
2.GPU负责栅格化及渲染(将UI元素渲染到屏幕上);
3.16ms发出VSYNC信号触发UI渲染;
4.大多数的Android设备屏幕刷新频率:60Hz;

二.优化工具:

1.Systrace:
 1).关注Frames
 2).正常:绿色圆点;丢帧:黄色或红色圆点;
 3).Alerts栏(根据信息查找修改方向);
2.Layout Inspector(AS自带工具):
 1).查看视图层次结构;
3.Choreographer类
 1).获取FPS,线上使用,具备实时性;
  a.API16之后使用;
  b.Choreographer.getInstance().postFrameCallBack;

三.Android布局加载原理:

微信图片_20210506204214.png

性能瓶颈:
1.布局文件解析:IO过程;
2.创建View对象:反射;
LayoutInflater.Factory:
1.LayoutInflater创建View的一个Hook;
2.定制创建View的过程:全局替换自定义TextView等;
Factory与Factory2:Factory2继承于Factory;多了一个参数:parent;

四.优雅获取界面布局耗时:

1.常规方式:
 背景:获取每个界面加载耗时
 实现:复写方法,手动埋点;
 缺点:不优雅,代码有侵入性;
2.AOP实现:
 切点:Activity的setContentView
 @Around("execution(*android.app.Activity.setContentView(..))")
3.ARTHook实现
4.如何获取每个控件加载耗时?
 1).低侵入性;
 2).使用LayoutInflater.Factory;

五.异步Inflate:

背景介绍:
 布局文件读取慢:IO过程;
 创建View慢:反射(比new慢3倍);
思路介绍:
 1.根本性的解决:从IO及反射慢入手解决;
 2.侧面缓解:不影响主线程,在主线程不耗时;
 AsyncLayoutInflater:简称异步Inflate
 1.WorkThread(工作线程)加载布局;
 2.回调主线程;
 3.节约主线程时间;
 缺点:
 不能设置LayoutInflater.Factory,未向下兼容,需要自定义AsyncLayoutInflater
 注意View中不能有依赖主线程的操作;

六.布局加载优化实战

背景介绍:
 1.IO操作,反射慢
 2.AsynclayoutInflater只是缓解;
Java代码写布局:本质上解决性能问题,引入新问题:不便于开发,可维护性差;
X2C介绍:保留XML优点,解决其性能问题
 1.开发人员写XML,加载java代码;
 2.原理:APT编译期翻译XML为Java代码;
 缺点:
 部分属性Java不支持;
 失去了系统的兼容(AppCompat),可自己修改框架;

七.视图绘制优化实战

绘制流程:
 1.测量:确定大小;
 2.布局:确定位置;
 3.绘制:绘制视图;
性能瓶颈:
 1.每个阶段耗时;
 2.自顶向下的遍历;
 3.触发多次;
布局层级及复杂度:
 准则:减少View数层级;宽而浅,避免窄而深;
ConstraintLayout:
 1.实现几乎完全扁平化;
 2.构建复杂布局性能更高;
 3.具有RelativeLayout和LinearLayout特性;
优化:
 1.不嵌套使用RelativeLayout;
 2.不在嵌套LinearLayout中使用weight;
 3.merger标签:减少一个层级,只能用于根View;
过度绘制:
 1.一个像素最好只被绘制一次;
 2.调试GPU过度绘制;
 3.蓝色可接受;
避免过度绘制的方法:
 1.去掉多余背景色,减少复杂shape使用;
 2.避免层级叠加;
 3.自定义View使用clipRect屏蔽被遮盖View绘制;
其他技巧:
 1.Viewstub:高效占位符,延迟初始化;
 2.onDraw中避免:创建大对象,耗时操作
 3.TextView优化

八.布局优化模拟面试

1.在布局优化过程中使用到那些工具?
 综合使用:ChoreoGrapher,AOP,HooK,Systrace,Layout Inspector;
2.布局为何导致卡顿,怎么优化?
 原因:IO,反射,遍历,重绘;
 解决:异步Inflate,X2C,减少布局层级,避免重绘等;
 AOP,监控;
3.做完布局优化产出?
 1.体系化监控手段:线下+线上;
 2.指标:FPS,加载时间,布局层级;
 3.核心路径保障;