布局优化
相关参考: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.inflate
Resources.getLayout
:解析xml
IO 耗时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
标签:可以减少一个层级,用于根View
ViewStub
:可以在真正需要使用时才加载布局避免过度绘制:官方文档
- 减少多余背景色,减少复杂的
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