HarmonyOS 鸿蒙Next的列表是怎么复用的呢?
HarmonyOS 鸿蒙Next的列表是怎么复用的呢? 列表复用item都需要做什么呢?都有哪几种复用方式?什么情况用什么呢?
keyGenerator
先说一下这个最常见的,Foreach和LazyForeach的第三个参数,在某些地方也会叫它key。
它有默认的生成规则,Foreach和LazyForeach还不完全相同,但是都是包含Index的。每个item都会按照这个默认规则或者你给的规则,生成一个key和item进行绑定。然后根据这个key来复用item。所以呢,如果你的列表不涉及到列表项index的变换,其实默认规则就够用了。但如果涉及到了,比如从头新增数据,中间数据的增加删除,列表项位置的变更等逻辑,那就得用唯一id了,比如数据源里自带的最好。反正不能带index,也不要弄的很乱有重复的。都会影响复用机制甚至数据错乱。
| 场景 | ForEach | LazyForEach |
|---|---|---|
| 默认键值规则 | index + "_" + JSON.stringify(item) |
viewId + '-' + index |
| 自定义keyGenerator未含index时 | 可能隐式拼接index |
严格按自定义规则生成 |
| 动态数据操作风险 | 较高(因默认含index) |
极高(默认完全依赖index) |
| 优化建议 | 静态数据可用默认规则 | 动态操作必须自定义唯一标识 |
它的复用,其实不是复用Item这个控件的实例,它是根据这个key来找要更新item是否存在,存在的话就直接更新这个叫这个key的item的数据,如果不存在就会重新创建一个item来给他设置上这个数据。
但在这个东西下面的所有创造字眼都不是真正的创建一个控件实例,再给他赋值,而是用现成的实例来赋值。这就要涉及到另一种控件实例的复用了,就是下一个要讲的。
List的复用机制
书接上文,鸿蒙系统本身就给List做了一个控件实例的复用机制,他会根据item的布局是否一致,能否复用,来直接给你进行控件实例复用,也就是说。你什么都不写,list自带着复用机制呢。不会每个item都给你重新创建控件实例,再去赋值。那keyGenerator和这个机制结合起来看就变成了。keyGenerator一致与否只是全量更新还是增量更新的区别了。但是这个机制也有它的局限性,比如你的item布局比较复杂了,它就识别的不太行了,这时候就要引申出来额外的复用机制或者说是性能优化方案了。
@Reusable和reuseId
当你的item布局比较复杂,或者是同一个列表,多种item布局类型。都适用这种额外优化方案。 你需要给你的布局加上 @Reusable直接告诉系统,你这个是可以被复用的。并且结合reuseId,帮助系统去区分,哪个和哪个是同一个布局,可以进行复用。这是对系统能力的补充,防止因为布局等逻辑情况复杂,让系统识别错误,导致该复用的没复用,产生额外的开销,或者复用错了,导致错位等情况。下面举个例子
// 文本项组件
[@Reusable](/user/Reusable)
@Component
struct TextItem {
@Prop text: string;
build() { Text(this.text).reuseId('text_item') }
}
// 图片项组件
[@Reusable](/user/Reusable)
@Component
struct ImageItem {
@Prop url: string;
build() { Image(this.url).reuseId('image_item') }
}
// 列表渲染
LazyForEach(this.dataSource, (item) => {
ListItem() {
if (item.type === 'text') {
TextItem({ text: item.content })
} else {
ImageItem({ url: item.url })
}
}
}, (item) => item.id) // key保证数据唯一性
LazyForeach的内存优化机制
最后再说一下LazyForeach的机制。这个东西其实主要就是用来做分页加载的,但是呢它也有它独特的优化机制。他会在列表项移动出视线后,进行内存释放,而不是像Foreach。虽然做了复用优化,但滑动走的item也都一直持有着呢。当然说是释放或者销毁了,但其实如果没被系统回收掉,依然在缓存池可以找到。也就是说,你再次向后滑或者向前滑,之前讲的那个复用机制依然是存在的。当然你可以根据实际情况设置它缓存池的大小,这样来具体情况具体优化。再细节的使用就自己看官方文档了,比如LazyForeach使使用时数据源要实现IDataSource接口,还有里面的方法。还有动态更新数据要维护aboutToReuse方法等等。
总结一下
keyGenerator不涉及到index更改就用默认的,否则要用唯一id
List系统本身就带着item控件实例复用机制呢
item布局复杂了要用@Reusable和reuseId
超长列表记得用LazyForeach
更多关于HarmonyOS 鸿蒙Next的列表是怎么复用的呢?的实战系列教程也可以访问 https://www.itying.com/category-93-b0.html
👍
👍
HarmonyOS Next的列表复用通过ArkUI的LazyForEach组件实现。该组件配合数据源和自定义组件,仅在可视区域渲染列表项。当列表滚动时,离开屏幕的组件实例会被回收并用于新进入屏幕的数据项,从而复用UI组件结构,避免重复创建销毁,以优化内存和性能。
在HarmonyOS Next中,列表项(item)的复用主要通过ArkUI的LazyForEach和ForEach组件来实现,这是提升长列表性能的核心机制。
1. 需要做什么(实现复用的关键步骤):
- 数据源准备:创建一个实现了
IDataSource接口的数据源类。这个类负责管理列表的数据集合,并能够根据索引(index)返回对应的数据项和唯一键(key)。 - 使用LazyForEach组件:在UI的
List、Grid或Swiper等滚动容器中,使用LazyForEach来迭代你的数据源。 - 提供项生成函数:为
LazyForEach提供一个itemGenerator函数。这个函数仅在item需要被创建或复用时才会被调用。它接收当前数据项和索引,并返回对应的UI组件。 - 关键属性(key):确保数据源为每个数据项提供一个稳定且唯一的
key。这个key是框架识别和复用item的唯一标识。如果key发生变化,框架会销毁旧item并创建新item。
2. 复用方式: 本质上,HarmonyOS Next的列表复用是一种基于组件生命周期的自动复用,主要分为两种场景:
LazyForEach(懒加载复用):这是处理长列表的标准且推荐的方式。它严格遵循“按需创建/复用”原则:只有当item即将滚动到视口(或可视区域)时,框架才会调用itemGenerator来创建或获取一个可复用的UI组件实例,并绑定新数据。离开视口的item会被框架回收至复用池,待需要时绑定新数据重新使用。这能极大减少内存占用和初始渲染开销。ForEach(全量创建,局部复用):通常用于静态、数据量较小的列表。它会立即为数据源中的每个数据项都创建对应的UI组件。虽然在其内部item(如ListItem)发生位置移动时,框架也会尝试复用UI结构,但其初始渲染开销较大,不适用于长列表。
3. 如何选择:
- 绝大多数情况,尤其是列表数据项数量多或不确定时,应使用
LazyForEach。这是ArkUI为优化性能设计的主要复用机制。 - 仅当列表数据项非常少(例如少于10个),且结构简单,或者需要所有item立即渲染时,才考虑使用
ForEach。
简单来说:实现列表复用的核心是使用LazyForEach组件配合实现了IDataSource接口的数据源,并为每个数据项提供唯一的key。框架会根据key和可视区域自动管理UI组件的创建、数据绑定和回收复用。

