HarmonyOS 鸿蒙Next ArkTS语言教程入门学习第28天,LazyForEach:数据懒加载。

发布于 1周前 作者 yuanlaile 来自 鸿蒙OS

HarmonyOS 鸿蒙Next ArkTS语言教程入门学习第28天,LazyForEach:数据懒加载。

LazyForEach:数据懒加载

LazyForEach从提供的数据源中按需迭代数据,并在每次迭代过程中创建相应的组件。当在滚动容器中使用了LazyForEach,框架会根据滚动容器可视区域按需创建组件,当组件滑出可视区域外时,框架会进行组件销毁回收以降低内存占用。

接口描述

LazyForEach(
    dataSource: IDataSource,             // 需要进行数据迭代的数据源
    itemGenerator: (item: any, index: number) => void,  // 子组件生成函数
    keyGenerator?: (item: any, index: number) => string // 键值生成函数
): void

参数:

参数名 参数类型 必填 参数描述
dataSource IDataSource LazyForEach数据源,需要开发者实现相关接口。
itemGenerator (item: any, index: number) => void 子组件生成函数,为数组中的每一个数据项创建一个子组件。
keyGenerator (item: any, index: number) => string 键值生成函数,用于给数据源中的每一个数据项生成唯一且固定的键值。

说明:

  • item是当前数据项,index是数据项索引值。
  • itemGenerator的函数体必须使用大括号{…}。itemGenerator每次迭代只能并且必须生成一个子组件。
  • itemGenerator中可以使用if语句,但是必须保证if语句每个分支都会创建一个相同类型的子组件。
  • itemGenerator中不允许使用ForEach和LazyForEach语句。

IDataSource类型说明

interface IDataSource {
    totalCount(): number; // 获得数据总数
    getData(index: number): Object; // 获取索引值对应的数据
    registerDataChangeListener(listener: DataChangeListener): void; // 注册数据改变的监听器
    unregisterDataChangeListener(listener: DataChangeListener): void; // 注销数据改变的监听器
}

接口声明

接口声明 参数类型 说明
totalCount(): number - 获得数据总数。
getData(index: number): any number 获取索引值index对应的数据。
registerDataChangeListener(listener: DataChangeListener): void DataChangeListener 注册数据改变的监听器。
unregisterDataChangeListener(listener: DataChangeListener): void DataChangeListener 注销数据改变的监听器。

DataChangeListener类型说明

interface DataChangeListener {
    onDataReloaded(): void; // 重新加载数据完成后调用
    onDataAdded(index: number): void; // 添加数据完成后调用
    onDataMoved(from: number, to: number): void; // 数据移动起始位置与数据移动目标位置交换完成后调用
    onDataDeleted(index: number): void; // 删除数据完成后调用
    onDataChange(index: number): void; // 改变数据完成后调用
    onDataAdd(index: number): void; // 添加数据完成后调用
    onDataMove(from: number, to: number): void; // 数据移动起始位置与数据移动目标位置交换完成后调用
    onDataDelete(index: number): void; // 删除数据完成后调用
    onDataChange(index: number): void; // 改变数据完成后调用
}

说明:

  • item是当前数据项,index是数据项索引值。
  • 数据源中的每一个数据项生成的键值不能重复。

使用限制

  • LazyForEach必须在容器组件内使用,仅有List、Grid、Swiper以及WaterFlow组件支持数据懒加载(可配置cachedCount属性,即只加载可视部分以及其前后少量数据用于缓冲),其他组件仍然是一次性加载所有的数据。
  • LazyForEach在每次迭代中,必须创建且只允许创建一个子组件。
  • 生成的子组件必须是允许包含在LazyForEach父容器组件中的子组件。
  • 允许LazyForEach包含在if/else条件渲染语句中,也允许LazyForEach中出现if/else条件渲染语句。
  • 键值生成器必须针对每个数据生成唯一的值,如果键值相同,将导致键值相同的UI组件渲染出现问题。
  • LazyForEach必须使用DataChangeListener对象来进行更新,第一个参数dataSource使用状态变量时,状态变量改变不会触发LazyForEach的UI刷新。
  • 为了高性能渲染,通过DataChangeListener对象的onDataChange方法来更新UI时,需要生成不同于原来的键值来触发组件刷新。

键值生成规则

在LazyForEach循环渲染过程中,系统会为每个item生成一个唯一且持久的键值,用于标识对应的组件。当这个键值变化时,ArkUI框架将视为该数组元素已被替换或修改,并会基于新的键值创建一个新的组件。

LazyForEach提供了一个名为keyGenerator的参数,这是一个函数,开发者可以通过它自定义键值的生成规则。如果开发者没有定义keyGenerator函数,则ArkUI框架会使用默认的键值生成函数,即(item: any, index: number) => { return viewId + ‘-’ + index.toString(); }, viewId在编译器转换过程中生成,同一个LazyForEach组件内其viewId是一致的。

组件创建规则

在确定键值生成规则后,LazyForEach的第二个参数itemGenerator函数会根据键值生成规则为数据源的每个数组项创建组件。组件的创建包括两种情况:LazyForEach首次渲染和LazyForEach非首次渲染。

首次渲染

在LazyForEach首次渲染时,会根据上述键值生成规则为数据源的每个数组项生成唯一键值,并创建相应的组件。

非首次渲染

当LazyForEach数据源发生变化,需要再次渲染时,开发者应根据数据源的变化情况调用listener对应的接口,通知LazyForEach做相应的更新,各使用场景如下。

添加数据

当我们点击LazyForEach的子组件时,首先调用数据源data的pushData方法,该方法会在数据源末尾添加数据并调用notifyDataAdd方法。在notifyDataAdd方法内会又调用listener.onDataAdd方法,该方法会通知LazyForEach在该处有数据添加,LazyForEach便会在该索引处新建子组件。

删除数据

当我们点击LazyForEach的子组件时,首先调用数据源data的deleteData方法,该方法会删除数据源对应索引处的数据并调用notifyDataDelete方法。在notifyDataDelete方法内会又调用listener.onDataDelete方法,该方法会通知LazyForEach在该处有数据删除,LazyForEach便会在该索引处删除对应子组件。

交换数据

当我们首次点击LazyForEach的子组件时,在moved成员变量内存入要移动的数据索引,再次点击LazyForEach另一个子组件时,我们将首次点击的子组件移到此处。调用数据源data的moveData方法,该方法会将数据源对应数据移动到预期的位置并调用notifyDataMove方法。在notifyDataMove方法内会又调用listener.onDataMove方法,该方法通知LazyForEach在该处有数据需要移动,LazyForEach便会将from和to索引处的子组件进行位置调换。

改变单个数据

当我们点击LazyForEach的子组件时,首先改变当前数据,然后调用数据源data的changeData方法,在该方法内会调用notifyDataChange方法。在notifyDataChange方法内会又调用listener.onDataChange方法,该方法通知LazyForEach组件该处有数据发生变化,LazyForEach便会在对应索引处重建子组件。

改变多个数据

当我们点击LazyForEach的子组件时,首先调用data的modifyAllData方法改变了数据源中的所有数据,然后调用数据源的reloadData方法,在该方法内会调用notifyDataReload方法。在notifyDataReload方法内会又调用listener.onDataReloaded方法,通知LazyForEach需要重建所有子节点。LazyForEach会将原所有数据项和新所有数据项一一做键值比对,若有相同键值则使用缓存,若键值不同则重新构建。

改变数据子属性

若仅靠LazyForEach的刷新机制,当item变化时若想更新子组件,需要将原来的子组件全部销毁再重新构建,在子组件结构较为复杂的情况下,靠改变键值去刷新渲染性能较低。因此框架提供了@Observed@ObjectLink机制进行深度观测,可以做到仅刷新使用了该属性的组件,提高渲染性能。开发者可根据其自身业务特点选择使用哪种刷新方式。

常见使用问题

渲染结果非预期

在删除一个数据项后调用reloadData方法,重建后面的数据项,以达到更新index索引的目的。

重渲染时图片闪烁

为了解决这种情况我们应该使用@ObjectLink@Observed去单独刷新使用了item.message的Text组件。

@ObjectLink属性变化UI未更新

@ObjectLink装饰的成员变量仅能监听到其子属性的变化,再深入嵌套的属性便无法观测到了,因此我们只能改变它的子属性去通知对应组件重新渲染,具体请查看@ObjectLink@Observed的详细使用方法和限制条件。


更多关于HarmonyOS 鸿蒙Next ArkTS语言教程入门学习第28天,LazyForEach:数据懒加载。的实战系列教程也可以访问 https://www.itying.com/category-93-b0.html

2 回复

在HarmonyOS中,LazyForEach 是一种用于懒加载数据的组件,适用于处理大量数据列表的场景。它通过动态加载数据来优化性能,避免一次性加载所有数据导致的内存和性能问题。

LazyForEach 的基本用法如下:

@Entry
@Component
struct LazyForEachExample {
  private dataList: Array<string> = ['Item1', 'Item2', 'Item3', 'Item4', 'Item5'];

  build() {
    Column() {
      LazyForEach(this.dataList, (item: string) => {
        Text(item)
          .fontSize(20)
          .margin(10)
      }, (item: string) => item)
    }
  }
}

参数说明:

  1. 数据源LazyForEach 的第一个参数是数据源,通常是一个数组或列表。
  2. 渲染函数:第二个参数是一个函数,用于定义如何渲染每个数据项。
  3. 唯一标识符:第三个参数是一个函数,用于为每个数据项生成唯一标识符,通常使用数据项本身的唯一属性。

特点:

  • 懒加载LazyForEach 只会在数据项即将显示时进行渲染,而不是一次性渲染所有数据。
  • 性能优化:适用于处理大量数据,避免内存占用过高和渲染性能下降。
  • 动态更新:当数据源发生变化时,LazyForEach 会自动更新渲染内容。

注意事项:

  • LazyForEach 适用于需要滚动加载的场景,如长列表或网格布局。
  • 确保为每个数据项提供唯一的标识符,以便系统正确识别和更新数据项。

通过使用 LazyForEach,开发者可以在鸿蒙系统中高效地处理大量数据,提升应用的性能和用户体验。

更多关于HarmonyOS 鸿蒙Next ArkTS语言教程入门学习第28天,LazyForEach:数据懒加载。的实战系列教程也可以访问 https://www.itying.com/category-93-b0.html


在第28天的HarmonyOS鸿蒙Next ArkTS语言教程中,您将学习到LazyForEach的使用,这是一种用于数据懒加载的技术。LazyForEach允许您在需要时才加载数据,从而优化性能,特别是在处理大量数据时。通过这种方式,您可以减少初始加载时间,提升应用的响应速度。教程将详细介绍如何实现LazyForEach,并展示其在列表或网格视图中的应用场景,帮助您更高效地管理数据加载。

回到顶部
AI 助手
你好,我是IT营的 AI 助手
您可以尝试点击下方的快捷入口开启体验!