鸿蒙NEXT开发【组件复用最佳实践】性能分析

概述

若开发者的应用中存在以下场景,并成为UI线程的帧率瓶颈,应该考虑使用组件复用机制提升应用性能:

  • 列表滚动(本例中的场景):当应用需要展示大量数据的列表,并且用户进行滚动操作时,频繁创建和销毁列表项的视图可能导致卡顿和性能问题。在这种情况下,使用列表组件的组件复用机制可以重用已经创建的列表项视图,提高滚动的流畅度。
  • 动态布局更新:如果应用中的界面需要频繁地进行布局更新,例如根据用户的操作或数据变化动态改变视图结构和样式,重复创建和销毁视图可能导致频繁的布局计算,影响帧率。在这种情况下,使用组件复用可以避免不必要的视图创建和布局计算,提高性能。
  • 地图渲染:在地图渲染这种场景下,频繁创建和销毁数据项的视图可能导致性能问题。使用组件复用可以重用已创建的视图,只更新数据的内容,减少视图的创建和销毁,能有效提高性能。

HarmonyOS应用框架提供了组件复用能力:可复用组件从组件树上移除时,会进入到一个回收缓存区,后续创建新组件节点时,会复用缓存区中的节点,节约组件重新创建的时间。

本文会介绍如何使用组件复用机制提升应用帧率。

组件复用原理与使用

原理介绍

组件复用机制如下:

  1. 标记为@Reusable的组件从组件树上被移除时,组件和其对应的JSView对象都会被放入复用缓存中。
  2. 当列表滑动新的ListItem将要被显示,List组件树上需要新建节点时,将会从复用缓存中查找可复用的组件节点。
  3. 找到可复用节点并对其进行更新后添加到组件树中。从而节省了组件节点和JSView对象的创建时间。

图1 组件复用原理图

1

1、@Reusable表示组件可以被复用,结合LazyForEach懒加载一起使用,可以进一步解决列表滑动场景的瓶颈问题,提供滑动场景下高性能创建组件的方式来提升滑动帧率。

2、CustomNode是一种自定义的虚拟节点,它可以用来缓存列表中的某些内容,以提高性能和减少不必要的渲染。通过使用CustomNode,可以实现只渲染当前可见区域内的数据项,将未显示的数据项缓存起来,从而减少渲染的数量,提高性能。

3、RecycleManager是一种用于优化资源利用的回收管理器。当一个数据项滚出屏幕时,不会立即销毁对应的视图对象,而是将该视图对象放入复用池中。当新的数据项需要在屏幕上展示时,RecycleManager会从复用池中取出一个已经存在的视图对象,并将新的数据绑定到该视图上,从而避免频繁的创建和销毁过程。通过使用RecycleManager,可以大大减少创建和销毁视图的次数,提高列表的滚动流畅度和性能表现。

4、CachedRecycleNodes是CustomNode的一个集合,常是用于存储被回收的CustomNode对象,以便在需要时进行复用。

说明

需要注意的是,虽然这里是使用List组件进行举例,但是不代表组件复用只能用在滚动容器里,只要是发生了相同自定义组件销毁和再创建的场景,都可以使用组件复用。

使用规则

组件复用的示例代码如下:

// xxx.ets
export class Message {
  value: string | undefined;

  constructor(value: string) {
    this.value = value
  }
}

@Entry
@Component
struct Index {
  @State switch: boolean = true
  build() {
    Column() {
      Button('Hello World')
        .fontSize(50)
        .fontWeight(FontWeight.Bold)
        .onClick(() => {
          this.switch = !this.switch
        })
      if (this.switch) {
        Child({ message: new Message('Child') })
          // 如果只有一个复用的组件,可以不用设置reuseId
          .reuseId('Child')
      }
    }
    .height("100%")
    .width('100%')
  }
}

@Reusable
@Component
struct Child {
  @State message: Message = new Message('AboutToReuse');

  aboutToReuse(params: Record<string, ESObject>) {
    console.info("Recycle Child")
    this.message = params.message as Message
  }

  build() {
    Column() {
      Text(this.message.value)
        .fontSize(20)
    }
    .borderWidth(2)
    .height(100)
  }
}

1.@Reusable:自定义组件被@Reusable装饰器修饰,即表示其具备组件复用的能力。

2.aboutToReuse:当一个可复用的自定义组件从复用缓存中重新加入到节点树时,触发aboutToReuse生命周期回调,并将组件的构造参数传递给aboutToReuse。

3.reuseId:用于标记自定义组件复用组,当组件回收复用时,复用框架将根据组件的reuseId来划分组件的复用组。如果只有一个复用的组件,可以不用设置reuseId。

组件复用优化方法

减少组件复用的嵌套层级

在组件复用场景下,过深的自定义组件的嵌套会增加组件复用的使用难度,比如需要逐个实现所有嵌套组件中aboutToReuse回调实现数据更新;因此推荐优先使用@Builder替代自定义组件,减少嵌套层级,利于维护且能提升页面加载速度。正反例如下:

反例:

@Entry
@Component
struct lessEmbeddedComponent {
  aboutToAppear(): void {
    getFriendMomentFromRawfile();
  }

  build() {
    Column() {
      List({ space: ListConstants.LIST_SPACE }) {
        LazyForEach(momentData, (moment: FriendMoment) => {
          ListItem() {
            OneMomentNoBuilder({moment: moment})
          }
        }, (moment: FriendMoment) => moment.id)
      }
      .cachedCount(Constants.CACHED_COUNT)
    }
  }
}

@Reusable
@Component
export struct OneMomentNoBuilder {
  @Prop moment: FriendMoment;

  // 无需对@Prop修饰的变量进行aboutToReuse赋值,因为这些变量是由父组件传递给子组件的。如果在子组件中重新赋值这些变量,会导致重用的组件的内容重新触发状态刷新,从而降低组件的复用性能。
  build() {
    ...
    // 在复用组件中嵌套使用自定义组件
    Row() {
      InteractiveButton({
        imageStr: $r('app.media.ic_share'),
        text: $r('app.string.friendMomentsPage_share')
      })
      Blank()
      InteractiveButton({
        imageStr: $r('app.media.ic_thumbsup'),
        text: $r('app.string.friendMomentsPage_thumbsup')
      })
      Blank()
      InteractiveButton({
        imageStr: $r('app.media.ic_message'),
        text: $r('app.string.friendMomentsPage_message')
      })
    }
    ...
  }
}

@Component
export struct InteractiveButton {
  @State imageStr: ResourceStr;
  @State text: ResourceStr;

  // 嵌套的组件中也需要实现aboutToReuse来进行UI的刷新
  aboutToReuse(params: Record<string, Object>): void {
    this.imageStr = params.imageStr as ResourceStr;
    this.text = params.text 
### HarmonyOS NEXT 性能优化技巧与最佳实践 HarmonyOS NEXT性能优化开发者在实际项目中必须关注的重点之一。以下将从多个方面详细介绍性能优化的技巧和最佳实践。 #### 1. 数据结构优化与属性访问 在 HarmonyOS NEXT 开发中,数据结构的选择和属性访问方式对性能有显著影响。通过合理设计数据结构,减少不必要的计算和内存占用,可以有效提升应用性能[^1]。例如,在日历组件案例中,开发者可以通过以下方法优化数据处理: - 使用高效的数组或对象结构替代复杂的数据模型。 - 减少深层嵌套的对象访问,尽量扁平化数据结构。 - 在属性访问时,优先使用本地缓存变量,避免频繁访问全局或远程对象。 #### 2. 主线程优化与异步处理 主线程的流畅性直接影响用户体验。为了避免主线程阻塞,应尽量将耗时操作移至后台线程执行[^3]。常见的优化手段包括: - 使用 `Worker` 或 `TaskDispatcher` 处理异步任务。 - 对于需要大量计算的场景,采用分批加载或懒加载策略。 - 通过事件驱动机制替代直接调用,降低主线程负担。 #### 3. 渲染优化 渲染性能是 HarmonyOS NEXT 应用优化的核心环节之一。为了提高渲染效率,可以采取以下措施: - 减少布局层级,避免过度嵌套的 UI 结构。 - 使用虚拟列表技术(Virtual List)优化长列表渲染。 - 启用 GPU 加速,减少 CPU 渲染压力。 - 在动画效果中,尽量使用硬件加速的属性(如 `translate`、`scale`),避免触发重绘。 #### 4. 资源管理与代码复用 资源管理和代码复用是提升应用性能的重要手段[^2]。开发者可以通过以下方式减少资源消耗并提高代码质量: - 合理压缩图片、音频等多媒体资源,避免加载过大的文件。 - 使用模块化开发,提高代码复用率,减少冗余逻辑。 - 定期清理无用的依赖库和资源文件,减少包体积。 #### 5. 系统架构与核心技术支持 了解 HarmonyOS NEXT 的系统架构和技术特性有助于开发者制定更有效的优化策略[^4]。例如: - 利用分布式软总线技术,优化多设备间的通信效率。 - 借助 FA(Feature Ability)和 PA(Particle Ability)的设计理念,实现轻量化功能模块。 - 结合 ArkTS 和 eTS 的语言特性,编写高性能代码。 #### 6. 性能分析工具的应用 性能优化离不开科学的分析工具。HarmonyOS NEXT 提供了多种性能分析工具,帮助开发者定位瓶颈并改进代码[^2]: - 使用 DevEco Studio 的性能分析器(Profiler)检测 CPU、内存、网络等方面的性能问题。 - 针对特定场景,采用方法级性能分析工具,深入挖掘代码中的潜在问题。 ```python # 示例:使用 TaskDispatcher 执行异步任务 import ability_slice from '@ohos.ability.slice'; import taskDispatcher from '@ohos.taskDispatcher'; export default class MainAbilitySlice extends ability_slice { onForeground() { const worker = taskDispatcher.createWorker(); worker.postMessage('Start background task'); worker.onmessage = (event) => { console.log('Background task result:', event.data); }; } } ``` ###
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值