HarmonyOS 鸿蒙Next中懒加载刷新UI

HarmonyOS 鸿蒙Next中懒加载刷新UI 初始列表有10条数据通过懒加载展示出来,当上拉到底部加载时接口会返回旧数据加新数据,为什么调用 listener.onDataReloaded() 列表页面不会实时刷新,但关闭列表页面然后重新打开就能看到新数据,该如何实现实时刷新

8 回复

没有具体的实现代码嘛,根据你的描述,写了类似的demo,看下是否可以

// BasicDataSource实现了IDataSource接口,用于管理listener监听,以及通知LazyForEach数据更新
class BasicDataSource implements IDataSource {
  private listeners: DataChangeListener[] = [];
  private originDataArray: string[] = [];

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

  public getData(index: number): string {
    return this.originDataArray[index];
  }

  // 该方法为框架侧调用,为LazyForEach组件向其数据源处添加listener监听
  registerDataChangeListener(listener: DataChangeListener): void {
    if (this.listeners.indexOf(listener) < 0) {
      console.info('add listener');
      this.listeners.push(listener);
    }
  }

  // 该方法为框架侧调用,为对应的LazyForEach组件在数据源处去除listener监听
  unregisterDataChangeListener(listener: DataChangeListener): void {
    const pos = this.listeners.indexOf(listener);
    if (pos >= 0) {
      console.info('remove listener');
      this.listeners.splice(pos, 1);
    }
  }

  // 通知LazyForEach组件需要重载所有子组件
  notifyDataReload(): void {
    this.listeners.forEach(listener => {
      listener.onDataReloaded();
    });
  }

  // 通知LazyForEach组件需要在index对应索引处添加子组件
  notifyDataAdd(index: number): void {
    this.listeners.forEach(listener => {
      listener.onDataAdd(index);
      // 写法2:listener.onDatasetChange([{type: DataOperationType.ADD, index: index}]);
    });
  }

  // 通知LazyForEach组件在index对应索引处数据有变化,需要重建该子组件
  notifyDataChange(index: number): void {
    this.listeners.forEach(listener => {
      listener.onDataChange(index);
      // 写法2:listener.onDatasetChange([{type: DataOperationType.CHANGE, index: index}]);
    });
  }

  // 通知LazyForEach组件需要在index对应索引处删除该子组件
  notifyDataDelete(index: number): void {
    this.listeners.forEach(listener => {
      listener.onDataDelete(index);
      // 写法2:listener.onDatasetChange([{type: DataOperationType.DELETE, index: index}]);
    });
  }

  // 通知LazyForEach组件将from索引和to索引处的子组件进行交换
  notifyDataMove(from: number, to: number): void {
    this.listeners.forEach(listener => {
      listener.onDataMove(from, to);
      // 写法2:listener.onDatasetChange(
      //         [{type: DataOperationType.EXCHANGE, index: {start: from, end: to}}]);
    });
  }

  notifyDatasetChange(operations: DataOperation[]): void {
    this.listeners.forEach(listener => {
      listener.onDatasetChange(operations);
    });
  }
}


class MyDataSource extends BasicDataSource {
  private dataArray: string[] = [];

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

  public getData(index: number): string {
    return this.dataArray[index];
  }

  public pushData(data: string): void {
    this.dataArray.push(data);
    this.notifyDataAdd(this.dataArray.length - 1);
  }
}

@Entry
@Component
struct PageDataReloaded {
  private data: MyDataSource = new MyDataSource();
  private isLoading = false

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

  build() {
    List({ space: 3 }) {
      LazyForEach(this.data, (item: string) => {
        ListItem() {
          Row() {
            Text(item)
              .onAppear(() => {
                console.info(`appear: ${item}`);
              })
          }
        }
      }, (item: string) => item)
    }
    .onReachEnd(() => {
      this.isLoading = true
      if (this.isLoading === true) {
        for (let i = 0; i <= 20; i++) {
          this.data.pushData(`Hello ${Math.random().toFixed(2)}`);
        }
        this.isLoading = false
      }
    })
  }
}

更多关于HarmonyOS 鸿蒙Next中懒加载刷新UI的实战系列教程也可以访问 https://www.itying.com/category-93-b0.html


我的数据是接口下发的对象数组,不是字符串数组,

  1. 也可以使用@ohos/pulltorefresh:一款下拉刷新、上拉加载组件。支持设置内置动画的各种属性,支持设置自定义动画,支持lazyForEarch的数据作为数据源。
  2. 也可以参考下拉刷新和上拉加载效果自定义,https://developer.huawei.com/consumer/cn/doc/architecture-guides/custom_refresh-0000002331948181 3.修改对象数组定义接口就可以
interface ItemData {
  id: string;
  text: string;
}

数据定义部分string[],及返回值string部分定义为ItemData

private originDataArray: ItemData[] = [];

public getData(index: number): ItemData {
  return this.originDataArray[index];
}
private dataArray: ItemData[] = [];

public getData(index: number): ItemData {
  return this.dataArray[index];
}

public pushData(data: ItemData): void {
  this.dataArray.push(data);
  this.notifyDataAdd(this.dataArray.length - 1);
}
aboutToAppear() {
  for (let i = 0; i <= 20; i++) {
    let id = util.generateRandomUUID()
    this.data.pushData({
      id,
      text: `Hello ${i}`
    });
  }
}

build() {
  List({ space: 3 }) {
    LazyForEach(this.data, (item: ItemData) => {
      ListItem() {
        Row() {
          Text(item.text)
            .onAppear(() => {
              console.info(`appear: ${item}`);
            })
        }
      }
    }, (item: ItemData) => JSON.stringify(item))
  }
  .onReachEnd(() => {
    this.isLoading = true
    if (this.isLoading === true) {
      for (let i = 0; i <= 20; i++) {
        let id = util.generateRandomUUID()
        this.data.pushData({
          id,
          text: `Hello ${Math.random().toFixed(2)}`
        });
      }
      this.isLoading = false
    }
  })
}

我一般使用三方库,实现上拉下拉刷新或加载更多数据

虽然不知道你的具体代码,但我建议早点更换成 Repeat 组件,我踩过坑

Repeat不支持V1装饰器… 没法换V2装饰器怎么办,

鸿蒙Next中懒加载刷新UI通过ArkUI的LazyForEach组件实现。该组件仅在列表项进入可视区域时动态创建组件,离开时销毁,优化内存使用。数据源需实现LazyDataSource接口,通过onDataReloaded()方法触发UI刷新。LazyForEach必须与List/Grid等滚动容器配合使用,数据变更时调用notifyDataChanged()通知更新。

在HarmonyOS Next中,listener.onDataReloaded() 方法可能未触发UI的即时重绘,原因通常是数据更新后未通知到UI组件进行刷新。建议使用 @State@Link 装饰器管理列表数据,并在数据变更后调用 this.listData = [...newData] 或使用 splice 等方法更新数组引用,以触发组件重新渲染。确保数据源更新后UI层能接收到变更通知,避免依赖页面重建来显示新数据。

回到顶部