布局优化
相关参考:https://androidperformance.com/2019/07/27/Android-Hardware-Layer/
优化工具
Systrace:- 关注
Frames行:正常绿色,丢帧黄色或红色 - 关注
Alerts栏:自动分析性能问题的一些条目
- 关注
Layout Inspector:Android Studio自带工具,查看视图层次结构
Choreographer:- 系统
api监控帧率:获取帧率
- 系统
uiautomatorviewer:- SDK 自带布局查看工具:
<SDK>/tools/bin/uiautomatorviewer.bat
- SDK 自带布局查看工具:
adb命令测试:
Android 布局加载原理
setContentView:调用LayoutInflater.inflateResources.getLayout:解析xmlIO 耗时LayoutInflater.createViewFromTag:通过Factory2、Factory和 反射创建View【备注:mPrivateFactory为创建Fragment用的】
从上述流程可知两个耗时点:加载 xml 的 IO 耗时,反射创建 View 耗时
【说明】Factory2 在 AppCompatActivity.onCraete 中设置,用于将 TextView 转换成 AppCompatTextView 等适配
【注意】如果要手动设置 Factory2 要参考 AppCompatViewInflater 的兼容实现
获取界面布局耗时
布局加载优化
一、异步创建布局:AsyncLayoutInflater
原理:内部开了单独一个线程专门用于异步创建 View,采用 ArrayBlockingQueue 队列做无限循环取数据,对于消息类还做了 SynchronizedPool 对象池,在子线程装载 View 失败还会在主线程再次装载一次
【注意一】由于采用系统自身的 Inflater 装载 View,会失去 AppCompat 的兼容效果,可以将源码拷贝出来修改成兼容将 TextView 转换成 AppCompatTextView 等适配
【注意二】由于是在子线程进行装载,待装载的 View 内部不能有依赖主线程的操作
二、Java 代码写布局
通过 xml 的方式编写布局,会有 IO 和反射耗时,可通过 Java 代码的方式从本质上解决性能问题。
该方式会引入新问题:不便于开发、可维护性差
三、X2C 方案
项目地址:https://github.com/iReaderAndroid/X2C
原理:通过 APT 编译期将 xml 文件翻译为 Java 布局文件
该方案保留了 xml 的优点,同时从根本上解决性能问题
【注意】该方案存在兼容性问题,部分属性 Java 代码时不支持的,同时也失去了 AppCompat 的兼容效果
进阶布局优化
一、异步布局框架 Litho
Litho 是 Facebook 开源的一款在Android上高效建立UI的声明式框架
PS:这里没有研究,自行参考官方文档实现方式
二、条件允许可以使用 Flutter
视图绘制优化
布局流程:测量 -> 布局 -> 绘制
减少每个布局流程的耗时
减少布局层级和复杂度:有的布局会多次测量,如果产生嵌套,就会呈几何上升的进行测量,推荐使用
ConstraintLayout约束布局不嵌套使用
RelativeLayout,会对子View做两次测量不在嵌套
LinearLayout中使用weight,会对子View做两次测量merge标签:可以减少一个层级,用于根ViewViewStub:可以在真正需要使用时才加载布局避免过度绘制:官方文档
- 减少多余背景色,减少复杂的
Shape的使用 - 避层级叠加
- 当在
onDraw中绘制的内容前后有产生覆盖的,需要使用clipRect来屏蔽被覆盖的区域,如果需要绘制的对象不在剪裁范围内,需要直接返回,减少CPU和GPU的计算工作,如前后绘制了两个有重叠的Bitmap
- 减少多余背景色,减少复杂的
避免在
onDraw中创建对象和执行耗时操作在
Android 5.0以下的自定义View触发刷新需要考虑刷新的范围invalidate(int l, int t, int r, int b),5.0 以上的直接invalidate()即可canvas在使用离屏缓存时很耗资源,范围设置为所需范围即可1
2
3val count = canvas.saveLayer(100f, 100f, 200f, 200f, paint)
// do something
canvas.restoreToCount(count)通过
Systrace发现每一帧都在buildDrawingCache/SW(主线程) 或buildLayer(渲染线程),那么需要检查代码的逻辑,尝试调整LayerType查看情况是否改良- 如果只是单纯的做动画,不动态修改 View 的内容,那么性能表现为 :Hardware Layer >= Software Layer > Normal Layer
- 如果做动画同时动态修改 View 的内容,那么性能表现为 :Normal Layer > Software Layer = Hardware Layer