HarmonyOS 鸿蒙Next ArkTS语言教程入门学习第28天,LazyForEach:数据懒加载。
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
在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)
}
}
}
参数说明:
- 数据源:
LazyForEach
的第一个参数是数据源,通常是一个数组或列表。 - 渲染函数:第二个参数是一个函数,用于定义如何渲染每个数据项。
- 唯一标识符:第三个参数是一个函数,用于为每个数据项生成唯一标识符,通常使用数据项本身的唯一属性。
特点:
- 懒加载:
LazyForEach
只会在数据项即将显示时进行渲染,而不是一次性渲染所有数据。 - 性能优化:适用于处理大量数据,避免内存占用过高和渲染性能下降。
- 动态更新:当数据源发生变化时,
LazyForEach
会自动更新渲染内容。
注意事项:
LazyForEach
适用于需要滚动加载的场景,如长列表或网格布局。- 确保为每个数据项提供唯一的标识符,以便系统正确识别和更新数据项。
通过使用 LazyForEach
,开发者可以在鸿蒙系统中高效地处理大量数据,提升应用的性能和用户体验。
更多关于HarmonyOS 鸿蒙Next ArkTS语言教程入门学习第28天,LazyForEach:数据懒加载。的实战系列教程也可以访问 https://www.itying.com/category-93-b0.html
在第28天的HarmonyOS鸿蒙Next ArkTS语言教程中,您将学习到LazyForEach
的使用,这是一种用于数据懒加载的技术。LazyForEach
允许您在需要时才加载数据,从而优化性能,特别是在处理大量数据时。通过这种方式,您可以减少初始加载时间,提升应用的响应速度。教程将详细介绍如何实现LazyForEach
,并展示其在列表或网格视图中的应用场景,帮助您更高效地管理数据加载。