【鸿蒙开发】[性能优化]ForEach与LazyForEach有什么区别?

部署运行你感兴趣的模型镜像

以下是 ForEach 的语法及其与 LazyForEach 的区别。

ForEach 的语法

ForEach 的基本使用方式如下:

ForEach(
  arr: Array<any>,                                   // 数据源数组
  itemGenerator: (item: any, index?: number) => void, // 子组件生成函数
  keyGenerator?: (item: any, index?: number) => string // 键值生成函数(可选)
)

示例代码

以下是 ForEach 的一个完整示例:

@Entry
@Component
struct Parent {
  @State simpleList: Array<string> = ['one', 'two', 'three'];

  build() {
    Row() {
      Column() {
        ForEach(this.simpleList, (item: string, index: number) => {
          ChildItem({ item: item })
        }, (item: string, index: number) => item)
      }
      .width('100%')
      .height('100%')
    }
    .height('100%')
    .backgroundColor(0xF1F3F5)
  }
}

@Component
struct ChildItem {
  @Prop item: string;

  build() {
    Text(this.item)
      .fontSize(50)
  }
}

LazyForEach 的语法

LazyForEach 的基本使用方式如下:


LazyForEach(
  dataSource: IDataSource,                             // 数据源
  itemGenerator: (item: any, index: number) => void,   // 子组件生成函数
  keyGenerator?: (item: any, index: number) => string // 键值生成函数(可选)
)

示例代码

以下是 LazyForEach 的一个完整示例:

@Entry
@Component
struct TestLazyForEachPage {
  @State message: string = '点击全部改变';
  private data: MyDataSource = new MyDataSource();

  aboutToAppear() {
    for (let i = 100; i >= 80; i--) {
      this.data.pushData(`Hello ${i}`);
    }
  }

  build() {
    Column() {
      Text(this.message)
        .width('100%')
        .height(80)
        .fontSize(25)
        .onClick(() => {
          let newData: string[] = [];
          for (let i = 10; i <= 30; i++) {
            newData.push(`Hello ${i}`);
          }
          this.data.freshData(newData);
          Prompt.showToast({ message: '改变了' });
        });

      List({ space: 3 }) {
        LazyForEach(this.data, (item: string, index: number) => {
          ListItem() {
            Row() {
              Text(item).fontSize(50)
                .onAppear(() => {
                  console.info("appear:" + item);
                });
            }.margin({ left: 10, right: 10 });
          }
          .onClick(() => {
            this.data.pushData(`Hello ${this.data.totalCount()}`);
          });
        }, (item: string, index: number) => item + index);
      }.cachedCount(5);
    }
    .width('100%')
    .height('100%');
  }
}

ForEach 与 LazyForEach 的区别

1.数据源类型:

○ForEach:直接接受一个数组作为数据源。
○LazyForEach:接受一个实现了 IDataSource 接口的对象作为数据源。

2.渲染策略:

○ForEach:一次性渲染所有数据项,适用于数据量较少的情况。
○LazyForEach:按需渲染数据项,只渲染可视区域内的数据项,适用于数据量较大的情况,提升性能。

3.内存使用:

○ForEach:会一次性加载所有的数据项,内存使用较高。
○LazyForEach:根据可视区域按需加载数据项,并回收滑出可视区域的数据项,内存使用较低。

4.组件复用:

○ForEach:没有内置的组件复用机制。
○LazyForEach:类似于原生开发中的 cell 复用机制,滑出可视区域的组件会被回收,新出现的组件优先使用复用池中的组件。

5.性能优化:

○ForEach:适用于数据量较少且性能要求不高的场景。
○LazyForEach:适用于数据量较大且性能要求较高的场景,显著提升页面性能和用户体验。

6.数据监听:

○ForEach:没有专门的数据监听机制,依赖于数组变化触发的 UI 更新。
○LazyForEach:需要通过 DataChangeListener 来监听数据变化,手动通知数据变动以刷新 UI。

使用场景

●ForEach:适用于静态数据或数据量较小的场景,例如简单的列表展示。
●LazyForEach:适用于动态数据或数据量较大的场景,例如新闻列表、商品列表等需要懒加载的页面。

通过理解上述区别,开发者可以根据具体需求选择合适的渲染方式来优化性能和用户体验。

另外, 关于LazyForEach实现IDataSource 接口

为什么需要实现 IDataSource 接口?

LazyForEach 组件用于处理大数据量时的按需渲染和懒加载,IDataSource 接口提供了一种标准化的方法来管理和访问这些数据。通过实现 IDataSource 接口,可以确保 LazyForEach 组件能够高效地处理数据,并在数据发生变化时正确地刷新 UI。

IDataSource 接口的作用

IDataSource 接口定义了一组方法,用于获取数据、监听数据变化等操作。具体包括:

1.totalCount() : 返回数据源中的数据总数。
2.getData(index: number) : 根据索引获取对应的数据项。
3.registerDataChangeListener(listener: DataChangeListener) : 注册数据变化的监听器。
4.unregisterDataChangeListener(listener: DataChangeListener) : 注销数据变化的监听器。
5.notifyDataReload() : 通知组件重新加载所有数据。
6.notifyDataAdd(index: number) : 通知组件在指定索引处添加数据。
7.notifyDataChange(index: number) : 通知组件在指定索引处的数据发生变化。
8.notifyDataDelete(index: number) : 通知组件在指定索引处删除数据。

实现 IDataSource 接口

通过实现 IDataSource 接口,开发者可以自定义数据源的行为,并确保 LazyForEach 能够正确地处理数据加载、数据变化等操作。下面是一个完整的实现示例:

interface IDataSource {
  totalCount(): number;
  getData(index: number): any;
  registerDataChangeListener(listener: DataChangeListener): void;
  unregisterDataChangeListener(listener: DataChangeListener): void;
  notifyDataReload(): void;
  notifyDataAdd(index: number): void;
  notifyDataChange(index: number): void;
  notifyDataDelete(index: number): void;
}

interface DataChangeListener {
  onDataReloaded(): void;
  onDataAdd(index: number): void;
  onDataChange(index: number): void;
  onDataDelete(index: number): void;
}

class BasicDataSource implements IDataSource {
  private listeners: DataChangeListener[] = [];
  private data: any[] = [];

  totalCount(): number {
    return this.data.length;
  }

  getData(index: number): any {
    return this.data[index];
  }

  registerDataChangeListener(listener: DataChangeListener): void {
    if (this.listeners.indexOf(listener) < 0) {
      this.listeners.push(listener);
    }
  }

  unregisterDataChangeListener(listener: DataChangeListener): void {
    const index = this.listeners.indexOf(listener);
    if (index >= 0) {
      this.listeners.splice(index, 1);
    }
  }

  notifyDataReload(): void {
    this.listeners.forEach(listener => listener.onDataReloaded());
  }

  notifyDataAdd(index: number): void {
    this.listeners.forEach(listener => listener.onDataAdd(index));
  }

  notifyDataChange(index: number): void {
    this.listeners.forEach(listener => listener.onDataChange(index));
  }

  notifyDataDelete(index: number): void {
    this.listeners.forEach(listener => listener.onDataDelete(index));
  }

  // Methods to manipulate data
  addData(data: any): void {
    this.data.push(data);
    this.notifyDataAdd(this.data.length - 1);
  }

  updateData(index: number, data: any): void {
    this.data[index] = data;
    this.notifyDataChange(index);
  }

  deleteData(index: number): void {
    this.data.splice(index, 1);
    this.notifyDataDelete(index);
  }
}

使用 LazyForEach 与 IDataSource

在使用 LazyForEach 时,需要将数据源传递给 LazyForEach 组件,并通过实现的 IDataSource 接口来管理数据。以下是使用 LazyForEach 的示例:

@Entry
@Component
struct TestLazyForEachPage {
  private data: BasicDataSource = new BasicDataSource();

  aboutToAppear() {
    for (let i = 0; i < 20; i++) {
      this.data.addData(`Item ${i}`);
    }
  }

  build() {
    Column() {
      List({ space: 3 }) {
        LazyForEach(this.data, (item: string, index: number) => {
          ListItem() {
            Row() {
              Text(item)
                .fontSize(20)
                .onAppear(() => {
                  console.info(`appear: ${item}`);
                });
            }.margin({ left: 10, right: 10 });
          }
          .onClick(() => {
            this.data.updateData(index, `${item} (clicked)`);
          });
        }, (item: string, index: number) => `${item}_${index}`);
      }.cachedCount(5);
    }
    .width('100%')
    .height('100%');
  }
}

结论

通过实现 IDataSource 接口,可以为 LazyForEach 提供灵活、高效的数据管理方式,确保在处理大数据量时能够按需加载数据,提升性能和用户体验。这也是 LazyForEach 与 ForEach 的主要区别之一:ForEach 适用于小数据量的全量渲染,而 LazyForEach 则专注于大数据量的按需渲染和懒加载。

写在最后

有很多小伙伴不知道该从哪里开始学习鸿蒙开发技术?也不知道鸿蒙开发的知识点重点掌握的又有哪些?自学时频繁踩坑,导致浪费大量时间。结果还是一知半解。所以有一份实用的鸿蒙(HarmonyOS NEXT)全栈开发资料用来跟着学习是非常有必要的。

获取完整版高清学习资料,请点击→鸿蒙全栈开发学习资料(安全链接,请放心点击)

这份鸿蒙(HarmonyOS NEXT)资料包含了鸿蒙开发必掌握的核心知识要点,内容包含了

最新鸿蒙全栈开发学习线路在这里插入图片描述

鸿蒙HarmonyOS开发教学视频

在这里插入图片描述

大厂面试真题

在这里插入图片描述

在这里插入图片描述

鸿蒙OpenHarmony源码剖析

在这里插入图片描述

这份资料能帮住各位小伙伴理清自己的学习思路,更加快捷有效的掌握鸿蒙开发的各种知识。有需要的小伙伴自行领取,,先到先得~无套路领取!!

获取这份完整版高清学习资料,请点击→鸿蒙全栈开发学习资料(安全链接,请放心点击)

您可能感兴趣的与本文相关的镜像

Stable-Diffusion-3.5

Stable-Diffusion-3.5

图片生成
Stable-Diffusion

Stable Diffusion 3.5 (SD 3.5) 是由 Stability AI 推出的新一代文本到图像生成模型,相比 3.0 版本,它提升了图像质量、运行速度和硬件效率

### 鸿蒙开发LazyForEach ForEach区别鸿蒙开发环境中,`LazyForEach` `ForEach` 是两种不同的循环渲染机制,主要用于处理不同规模的数据集。 #### 数据量适用范围 - **ForEach**: 主要适用于较小数据量的全量渲染场景。当数据量较小时,一次性加载所有数据不会对性能造成明显影响[^1]。 - **LazyForEach**: 更适合于大数据量的按需渲染懒加载需求。通过实现 `IDataSource` 接口,`LazyForEach` 可以为开发者提供一种灵活高效的管理方式,在处理大量数据时仅加载当前可见部分的内容,从而提高应用的整体性能并改善用户体验。 #### 支持的容器组件 两者都必须放置在一个合适的父级容器内部才能正常工作;然而对于特定类型的布局结构而言: - **ForEach**:几乎可以在任何支持子元素遍历操作的地方使用。 - **LazyForEach**:只有某些特殊设计用来配合其特性的高级UI控件才允许采用这种方式来呈现内容——具体来说就是 List、Grid、Swiper 或 WaterFlow 这样的滚动视图类部件[^2]。 #### 性能考量 考虑到实际应用场景中的效率问题: - **ForEach**:由于每次都会尝试创建整个列表的所有项目实例,因此更适合那些不需要特别关注资源消耗的小型集合展示任务[^3]。 - **LazyForEach**:针对大型数据源进行了专门优化,能够在保持良好交互流畅度的同时减少内存占用,非常适合构建高性能的应用界面。 ### 使用示例 以下是两个简单的代码片段展示了如何分别利用这两种方法来进行 UI 组件的迭代生成。 #### 使用 ForEach 渲染固定数量的简单卡片 ```xml <Stack> <div repeat="ForEach"> <!-- 卡片模板 --> <Card /> </div> </Stack> ``` #### 使用 LazyForEach 实现带分页效果的商品列表 ```xml <List> <template is="LazyForEach" source="{{dataSource}}" as="item"> <ProductItem data="{{item}}"/> </template> </List> ``` 注意这里假设有一个名为 `dataSource` 的变量作为商品项目的来源,并且每个产品项由 `<ProductItem>` 自定义标签表示。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值