布局性能优化
基本布局流程
在ArkUI的布局过程中,应用侧会根据前端UI描述创建后端的页面节点树,包含处理UI组件属性更新,布局测算,事件处理等逻辑。
例如上述布局:
- 应用会根据我们的代码,创建对应的node节点树,其中,
Custom Node
表示自定义组件节点,Frame Node
节点表示系统组件节点。 - 在这个过程中,UI线程会对每个元素进行测算
measure
和布局lauout
,来确定具体的位置和大小,measure
阶段负责确定组件的测量宽高,也就是该组件元素占用的屏幕大小,layout
阶段会确定最终宽高和四个顶点的位置。 - 根据页面节点树,生成当前界面描述数据结构–渲染树。渲染树由
RenderNode
渲染节点组成,描述了具体元素在屏幕上的布局信息,包含大小、位置以及一些其他属性。 - 渲染服务的渲染线程会根据渲染树的信息执行相应的绘制工作。
在布局阶段中,如果视图嵌套层级较深,或者页面节点过多,会导致在Measure和layout过程中,通过遍历测量组件大小和边界的时间过长。所以布局性能优化,可以从减少节点数或者优化布局测算时间方面来考虑。
精简节点数
首先我们先看一下相同数量节点嵌套和平铺的情况下,对性能的影响,通过使用IDE的profiler工具进行抓取,可以得知:
从上边我们可以看出,在相同组件、相同数量的情况下,嵌套和平铺对性能的影响差距不是很大,主要影响性能的还是节点数量,所以我们在进行布局的时候,应该尽量减少参与布局的节点数,来减少布局的性能消耗。
主要有两个优化方向:
- 移除冗余节点。
- 使用扁平化布局,减少层级嵌套,如
RelativeContainer
、Grid
等。
合理控制元素的隐藏与显示
在ArkUI中,控制元素隐藏和显示,一般有两种方式,使用条件语句控制,或者使用visibility属性来控制。
我们来对比使用条件渲染语句和使用visibility属性来控制时,measure和layout耗时区别:
首次渲染:
我们可以看到,使用条件渲染语句时,当条件为false时,对应组件不参与measure和layout阶段。使用visibility属性进行控制的时候,无论组件是否显示,都会参与measure阶段,如果visibility为none,那么组件不参与layout阶段。
切换显示
我们可以看到,切换显示状态的时候,使用条件渲染语句,会根据条件来判断组件是否创建,切换过程会出现较大的性能消耗,且每次切换消耗相同。使用visibility的时候,性能消耗要小很多。
综上所述,在控制组件的显示与隐藏时,我们可以遵循以下原则:
- 对性能要求较高,且会频繁切换显示与隐藏的情况下,使用visibility属性进行控制。
- 组件创建性能消耗较大,且初始状态下不可见,并且不会频繁切换的情况下,使用条件渲染语句进行控制。
给定组件的宽高
在ArkUI中,我们给组件设置宽高的方式,一般分为三种:设置固定值、百分比宽高、不设置宽高。
我们对比三种情况下的measure和layout的耗时
初次加载时,三种情况消耗差距不大,原因是初次加载的时候,所有的组件都参与了measure和layout过程。
在重绘的过程中,我们可以看到,给定宽高的组件,所消耗的性能明显小于其他两种方式,原因是修改宽高触发重绘的情况下, 给定内部组件宽高时,内部组件可以重用初次measure和layout数据,不设置宽高和百分比宽高的,由于父容器宽高发生了变化,所以需要参与measure和layout过程。
使用推荐的布局组件
越是复杂的布局,measure和layout的过程越是耗时,比如grid组件就会比row组件耗时,但是如果使用grid组件,可以明显减少页面的节点数量或者是嵌套层级数量,那么此时所节省的性能会明显优于grid组件多消耗的性能。
长列表加载性能优化
长列表优化概述
针对长列表加载场景,对列表渲染速度、页面滑动帧率、内存占用大小等方面进行优化,主要有以下几个方面
- 懒加载:提供列表数据按需加载的能力,解决一次性加载列表项耗时过长,占用过多资源的问题,提升页面加载速度。
- 缓存列表项:提供屏幕可视区域外列表缓存长度的自定义调节能力,配合懒加载使用,缓存页面数据,预加载页面外列表项,提升列表滑动体验。
- 组件复用:提供可复用组件对象的缓存资源池,通过重复使用已经创建并缓存的组件对象,降低相同组件短时间内频繁创建和销毁的消耗,提升渲染效率。
- 布局优化:使用扁平布局,减少视图嵌套层级和节点数,提升渲染效率。
懒加载
当列表数据量较小且布局较为简单的时候,我们可以使用ForEach渲染语句。
当列表数据量较大时,使用lazyForEach
渲染语句实现懒加载的效果。
使用lazyForEach渲染语句时,最小可以做到仅加载渲染屏幕当前显示的列表项。
缓存列表项
我们使用了lazyForEach懒加载时,默认只会渲染当前屏幕显示的列表项,那么当我们快速滑动的时候,就会出现白块的现象。
lazyForEach可以通过设置cachedCount
来缓存或预加载一定数量的列表项,比如当前屏幕最大可以显示5条,cachedCount为3,那么此时挂载在组件树上的列表项,最多可以是11条。
组件复用
- 在item列表项的自定义组件头部添加
@Reusable
装饰器,标识该组件拥有复用的能力。 - 实现可复用自定义组件的生命周期
aboutToReuse
方法,也就是我们的数据填充逻辑。 - 在ListItem组件上设置可复用组件的
ReuseId
。