
HarmonyOS开发实战指南:组件过度嵌套优化-ArkUI
通过ArkUI框架的执行流程,以及自定义组件的生命周期两个角度,来分析组件过度嵌套对性能的影响。
原理概述
通过ArkUI框架的执行流程,以及自定义组件的生命周期两个角度,来分析组件过度嵌套对性能的影响。
ArkUI框架执行流程
如上图所示,可以看到ArkUI框架的执行顺序:
- 执行ArKTS中的UI描述信息,通过UI描述API创建后端的页面节点树FrameNode树,其中包含了处理UI组件属性更新、布局测算、事件处理等业务逻辑;
- 通过FrameNode生成当前的界面描述数据结构——渲染树RenderTree,RenderTree描述了具体的元素在屏幕上的布局信息,包含大小、位置以及一些其他属性;
- 最后渲染线程会根据RenderTree的信息执行相应的绘制工作。
自定义组件的生命周期
如上图所示,自定义组件创建完成之后,在build函数执行之前,将先执行aboutToAppear()生命周期回调函数。执行完build函数后,还会有一些事件监听函数,例如可以使用onPageShow监听页面显示事件,onPageHide函数可以监听页面隐藏事件。最终在自定义组件析构销毁前执行aboutToDisappear函数。
组件过度嵌套对性能的影响
从ArkUI框架的执行流程上分析,组件的过度嵌套会导致节点树深度过高,由于对节点树的遍历方式为深度优先遍历,所以节点树深度过高则会影响性能,节点树应更更趋向于扁平化。
从自定义组件的生命周期的角度上分析,如果自定义组件过度嵌套,则会有大量的生命周期函数需要执行,消耗性能。
优化场景
优先使用@Builder方法代替自定义组件
自定义组件与自定义构建函数概念定义如下:
自定义组件:用@Component修饰的struct结构体称为自定义组件,在自定义组件中可以定义函数/变量、build()方法、组件的生命周期回调等。自定义组件具有可组合、可重用和数据驱动UI更新的特点
自定义构建函数:@Builder装饰的函数称为“自定义构建函数”,分为组件内自定义构建函数和全局自定义构建函数。@Builder所装饰的函数遵循build()函数语法规则,开发者可以将重复使用的UI元素抽象成一个方法,在build方法里调用。
自定义组件和自定义构建函数(@Builder)的主要区别如下:
1. 自定义构建函数(@Builder)更轻量,其作为UI元素抽象的方法,实现和调用相较于自定义组件比较简洁;
2. 在自定义组件中,可以定义成员函数/变量、自定义组件生命周期等; 自定义构建函数(@Builder)不支持定义状态变量和自定义生命周期;
3. 在自定义组件中,可直接通过状态变量的改变,来驱动UI的刷新。而自定义构建函数(@Builder)默认的按值参数传递方式不支持动态改变组件,当传递的参数为状态变量时,状态变量的改变不会引起@Builder方法内的UI刷新,要实现UI动态刷新需要按引用传递参数;
4. 在自定义组件中要实现插槽功能,需要使用@Builder和@BuiderParams实现。具体实现可参考:如何实现插槽和@BuilderParam装饰器:引用@Builder函数
5. 自定义构建函数(@Builder)中使用了自定义组件,那么该方法每次被调用时,对应的自定义组件均会重新创建。
整体上,自定义组件在实际应用开发场景中更加通用、灵活。自定义构建函数(@Builder)由于不支持定义变量和生命周期等限制,在使用场景上灵活性受限,多用在插槽或系统提供的组件/方法里面属性传值类型为Builder类型场景中。
根据上面自定义组件与自定义构建函数的区别可以看出,由于@Builder不涉及生命周期,在自定义组件大量嵌套的场景中,更加轻量级的@Builder在性能方面更加出色。
所以可以得出一下结论,当自定义组件不涉及到状态变量和自定义生命周期时,可以优先使用@Builder替换自定义组件,提升性能。
优化策略
自定义组件示例代码:
@Component
export struct example {
build() {
Column(){
Text('自定义组件示例代码')
...
}
}
}
自定义构建函数示例代码:
@Builder
export function example(){
Column(){
Text('自定义构建函数示例代码')
...
}
}
具体可以参考UI组件性能优化-优先使用@Builder方法代替自定义组件
选择合适的布局组件
复杂布局提供了场景化的能力,解决一种或者多种布局场景。但是在一些场景下,不恰当的使用这些高级组件,可能带来更多的性能消耗。
优化策略:
- 在相同嵌套层级的情况下,如果多种布局方式可以实现相同布局效果,优选低耗时的布局,如使用Column、Row替代Flex实现相同的单行布局;
- 在能够通过其他布局大幅优化节点数的情况下,可以使用高级组件替代,如使用RelativeContainer替代Row、Column实现扁平化布局,此时其收益大于布局组件本身的性能差距;
- 仅在必要的场景下使用高耗时的布局组件,如使用Flex实现折行布局、使用Grid实现二维网格布局等;
具体可以参考合理使用布局-合理使用布局组件
删除无用的Stack/Column/Row嵌套,移除冗余节点
在组件嵌套的情况中,可以找到一些无用的容器组件嵌套。在考虑组件嵌套优化中,可以删除掉无用容器组件嵌套,移除冗余节点,从而避免冗余节点对性能的消耗。
优化方式:
反例:
@Component
export struct example {
build() {
Column(){
Row(){
// 自定义组件
FlowListStruct({
// 自定义组件传递参数
...
})
}
.width('100%')
}
.width('100%')
.height('100%')
}
}
正例:
@Component
export struct example {
build() {
Column() {
// 自定义组件
FlowListStruct({
// 自定义组件传递参数
...
})
}
.width('100%')
.height('100%')
}
}
将自定义组件的属性移至自定义组件内部
给自定义组件添加属性时,实际上是给自定义组件套了一层不可见的组件,而给自定义组件添加的属性,实际上也是绑定在这层不可见的组件上的。所以,给自定义组件添加属性与自定义组件内部添加属性二者相比,自定义组件内部添加属性会少一层不可见组件,使得总节点数量降低,从而可以提升性能。
反例:
@Component
export struct example {
build() {
Column() {
// 自定义组件
FlowListStruct({
// 自定义组件传递参数
...
}).backgroundColor('#FFFFFF')
}
.width('100%')
.height('100%')
}
}
正例:
@Component
export struct FlowListStruct {
build(){
Column(){
...
}
.backgroundColor('#FFFFFF')
}
}
实践数据对比
关于实践数据对比部分,具体可以参考合理使用布局和UI组性能优化的数据对比部分。
最后
有很多小伙伴不知道学习哪些鸿蒙开发技术?不知道需要重点掌握哪些鸿蒙应用开发知识点?但是又不知道从哪里下手,而且学习时频繁踩坑,最终浪费大量时间。所以本人整理了一些比较合适的鸿蒙(HarmonyOS NEXT)学习路径和一些资料的整理供小伙伴学习
点击领取→纯血鸿蒙Next全套最新学习资料希望这一份鸿蒙学习资料能够给大家带来帮助,有需要的小伙伴自行领取~~
一、鸿蒙(HarmonyOS NEXT)最新学习路线
有了路线图,怎么能没有学习资料呢,小编也准备了一份联合鸿蒙官方发布笔记整理收纳的一套系统性的鸿蒙(OpenHarmony )学习手册(共计1236页)与鸿蒙(OpenHarmony )开发入门教学视频,内容包含:(ArkTS、ArkUI开发组件、Stage模型、多端部署、分布式应用开发、音频、视频、WebGL、OpenHarmony多媒体技术、Napi组件、OpenHarmony内核、Harmony南向开发、鸿蒙项目实战等等)鸿蒙(HarmonyOS NEXT)…等技术知识点。
获取以上完整版高清学习路线,请点击→纯血版全套鸿蒙HarmonyOS学习资料
二、HarmonyOS Next 最新全套视频教程
三、《鸿蒙 (OpenHarmony)开发基础到实战手册》
OpenHarmony北向、南向开发环境搭建
四、大厂面试必问面试题
五、鸿蒙南向开发技术
六、鸿蒙APP开发必备
完整鸿蒙HarmonyOS学习资料,请点击→纯血版全套鸿蒙HarmonyOS学习资料
总结
总的来说,华为鸿蒙不再兼容安卓,对中年程序员来说是一个挑战,也是一个机会。只有积极应对变化,不断学习和提升自己,他们才能在这个变革的时代中立于不败之地。
更多推荐
所有评论(0)