鸿蒙原生APP性能优化之全局自定义组件复用


📚鸿蒙开发往期学习笔录✒️:

✒️ 鸿蒙(OpenHarmony)南向开发保姆级知识点汇总~
✒️ 鸿蒙应用开发与鸿蒙系统开发哪个更有前景?
✒️ 嵌入式开发适不适合做鸿蒙南向开发?看完这篇你就了解了~
✒️ 对于大前端开发来说,转鸿蒙开发究竟是福还是祸?
✒️ 鸿蒙岗位需求突增!移动端、PC端、IoT到底该怎么选?
✒️ 记录一场鸿蒙开发岗位面试经历~
✒️ 持续更新中……


简介

默认的组件复用行为,是将子组件放在父组件的缓存池里,受到这个限制,不同父组件中的相同子组件无法复用,推荐的解决方案是将父组件改为builder函数,让子组件共享组件复用池,但是由于在一些应用场景下,父组件承载了复杂的带状态的业务逻辑,而builder是无状态的,修改会导致难以维护,因此开发者可以使用BuilderNode自行管理组件复用池。

实现思路

  1. 将要生成自定义组件地方用 NodeContainer 占位,将NodeContainer内部的 NodeController 按照组件类型分别存储在NodePool中。
  2. 每次创建子组件时,优先通过NodePool的getNode方法尝试复用已存在的NodeController组件,若无可复用组件则调用makeNode方法新建;若复用成功,则调用update方法更新组件数据。
  3. 当NodeController销毁时,NodeItem回收到NodePool中,供下次使用。

组件复用原理

在ArkUI中,当页面退出时,系统默认会销毁页面上的所有节点及其对应的NodeItem实例,以释放资源。为了提升性能和资源利用率,应用侧可以主动保存NodeItem实例。通过这种方法,能够有效延长这些NodeItem实例的生命周期,避免不必要的重建开销,从而在后续页面或组件的创建过程中实现快速复用。

下图为复用池中NodeItem实例跟随NodeContainer组件创建与销毁的复用过程。

数据结构

NodeItem继承NodeController,并实现makeNode方法,创建组件。NodePool通过HashMap管理NodeItem的复用和回收。

应用场景

在应用开发中,会遇到需要页面切换的场景,比如某些视频APP的首页,就是一个List(标题)+Swiper(列表页面)实现的Tabs切换场景。Swiper中每个页面都使用瀑布流加载视频列表,各个瀑布流中的子组件有可能是相同的布局,为了提升应用性能,就会有跨页面复用子组件的需求。但是在ArkUI提供的常规复用中,复用池是放在父组件中的,这就导致跨页面时无法复用上一个页面瀑布流中的子组件。此时就可以使用 BuilderNode 自定义一个全局的组件复用池,根据页面状态创建、回收、复用子组件,实现组件的跨页面复用。

组件复用性能对比

下面通过常规复用和自定义组件复用池两种方式,对比组件复用的性能。

常规复用

  • 使用List+Swiper实现Tabs页面切换。
List() {
  ForEach(this.arrayTitle, (title: Title, index: number) => {
    ListItem() {
      TitleView({
        title: title, clickListener: () => {
          if (title.isSelected) {
            return;
          }
          // 点击标题时,Swiper组件跳转到对应的页面
          this.swiperController.changeIndex(index, true);
          // 设置标题为选中状态
          this.arrayTitle[index].isSelected = true;
          this.arrayTitle[this.selectIndex].isSelected = false;
          this.selectIndex = index;
        }
      })
        // ...
    }
  })
}
.height(30)
.listDirection(Axis.Horizontal)

Swiper(this.swiperController) {
  // 使用LazyForEach,使Swiper页面按需加载,而不是一次全部创建
  LazyForEach(this.array, (item: string, index: number) => {
    // 常规复用代码,可按需注释运行
    // TabComp({ index: index })
    // 自定义组件复用池代码
    TabNode({ index: index })
  }, (title: string) => title)
}
.loop(false)
.onChange((index: number) => {
  // Swiper滑动切换页面时,改变标题栏的选中状态
  if (this.selectIndex !== index) {
    this.arrayTitle[index].isSelected = true;
    this.arrayTitle[this.selectIndex].isSelected = false;
    this.selectIndex = index;
  }
})
.cachedCount(0) // 此处设置cachedCount为0,便于性能对比,实际开发中可按需设置
  • 使用Swiper组件
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值