本文同步发表于我的微信公众号,微信搜索 程语新视界 即可关注,每个工作日都有文章更新
一、懒加载的核心类型与场景
1. 组件级懒加载
- LazyForEach 功能:动态加载长列表数据,仅渲染可视区域及附近缓冲项。
- 适用场景:
List、Grid、Swiper等容器组件中的大数据集渲染。 - 关键特性:
- 通过
cachedCount控制预加载数量(默认1) - 依赖
IDataSource接口实现数据驱动更新 - 示例代码:
- 通过
// 数据源实现
class ProductDataSource implements IDataSource {
private products: Product[] = [...];
registerDataChangeListener(listener: DataChangeListener): void {
// 注册数据变更监听
}
getData(index: number): Product {
return this.products[index];
}
}
// LazyForEach使用
List({ space: 10 }) {
LazyForEach(new ProductDataSource(), (item: Product) => {
ListItem() {
ProductItem({ item: item }) // 子组件需用@Reusable装饰
}
}, (item: Product) => item.id.toString()) // 唯一Key生成
}
- 注意事项:
- 子组件需添加
@Reusable装饰器以启用节点复用(@Reusable装饰器的使用) - 数据源变更需通过
DataChangeListener通知更新(如notifyDataAdd)
- 子组件需添加
2. 模块级懒加载
- 动态导入(lazy import) 功能:延迟加载非关键模块,减少冷启动时间。
- 语法:
import lazy { functionA } from './moduleA'; // 延迟加载
import { functionB } from './moduleB'; // 立即加载
- 使用场景:
- 冷启动阶段非必需的功能模块(如设置页、二级页面)
- 按需加载第三方库
- 注意事项:
- API 12+支持,需在
build-profile.json5配置compatibleSdkVersionStage: "beta3" - 同步加载可能阻塞主线程,需评估性能影响
3. Native NodeAdapter(C++层懒加载)
- 功能:替代ArkTS的
LazyForEach,适用于高性能要求的原生组件。 - 核心API:
OH_ArkUI_NodeAdapter_Create() // 创建Adapter
OH_ArkUI_NodeAdapter_SetTotalNodeCount() // 设置总项数
OH_ArkUI_NodeAdapter_RegisterEventReceiver() // 注册事件回调
- 事件类型:
NODE_ADAPTER_EVENT_ON_GET_NODE_ID:请求节点IDNODE_ADAPTER_EVENT_ON_REMOVE_NODE_FROM_ADAPTER:释放节点
优势:更精细的内存控制(需手动释放节点)、适用于WaterFlow等复杂布局
二、懒加载的进阶使用技巧
1. 性能优化策略
- 缓存策略:
// 复用已加载的组件
@Reusable
@Component
struct ProductItem {
@LocalStorageProp('productCache') cache: Map<string, Product> = new Map();
build() {
// 使用缓存数据
}
}
分页加载: 结合onScrollIndex事件动态追加数据:
List({ space: 10 }) {
LazyForEach(dataSource, (item) => {/* ... */})
.onScrollIndex((first: number) => {
if (first >= dataSource.totalCount() - 5) {
loadMoreData(); // 触发加载下一页
}
})
}
2. 数据删除处理
问题:子组件中删除LazyForEach数据需同步更新索引。
解决方案:
// 子组件触发删除
@Component
struct AddressItem {
@Prop item: ListItemData;
onDelete() {
this.onDeleteItem(true); // 回调父组件
}
build() {
Button('删除').onClick(() => this.onDelete())
}
}
// 父组件处理删除
LazyForEach(this.dataSource, (item, index) => {
ListItem() {
AddressItem({
item: item,
onDeleteItem: (isDelete) => {
if (isDelete) {
this.dataSource.deleteData(index); // 需传递正确索引
}
}
})
}
})
关键点:确保删除时索引与数据源一致。
三、调试与常见问题
1. 性能分析工具
- DevEco Profiler:监控内存占用与渲染帧率
- HiLog过滤:
hdc shell hilog | grep 'LazyForEach' # 查看懒加载日志
2. 典型问题解决
| 问题 | 解决方案 |
|---|---|
| 列表滑动卡顿 | 增加cachedCount(建议值:屏幕可见项数的1.5倍) |
| 动态导入阻塞UI | 使用TaskPool在子线程执行加载逻辑 |
| 节点复用失效 | 检查@Reusable装饰器与Key的唯一性 |
760

被折叠的 条评论
为什么被折叠?



