HarmonyOS/OpenHarmony application development-ArkTS language rendering control LazyForEach data lazy loading

LazyForEach iterates data on demand from the provided data source and creates the corresponding components during each iteration. When LazyForEach is used in a scrolling container, the framework will create components on demand based on the visible area of ​​the scrolling container. When the component is drawn outside the visible area, the framework will destroy and recycle the component to reduce memory usage.
1. Interface description

LazyForEach(
    dataSource: IDataSource,             // 需要进行数据迭代的数据源 
    itemGenerator: (item: any) => void,  // 子组件生成函数
    keyGenerator?: (item: any) => string // (可选) .键值生成函数
): void
interface IDataSource {
    totalCount(): number;                                             // Get total count of data
    getData(index: number): any;                                      // Get single data by index
    registerDataChangeListener(listener: DataChangeListener): void;   // Register listener to listening data changes
    unregisterDataChangeListener(listener: DataChangeListener): void; // Unregister listener
}
interface DataChangeListener {
    onDataReloaded(): void;                      // Called while data reloaded
    onDataAdd(index: number): void;            // Called while single data added
    onDataMove(from: number, to: number): void; // Called while single data moved
    onDataDelete(index: number): void;          // Called while single data deleted
    onDataChange(index: number): void;          // Called while single data changed
.}

HarmonyOS/OpenHarmony application development-ArkTS language rendering control LazyForEach data lazy loading-Open source basic software community


2. IDataSource type description

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

HarmonyOS/OpenHarmony application development-ArkTS language rendering control LazyForEach data lazy loading-Open source basic software community


3. DataChangeListener type description
 

HarmonyOS/OpenHarmony application development-ArkTS language rendering control LazyForEach data lazy loading-Open source basic software community


4. Usage restrictions
LazyForEach must be used within container components. Only List, Grid and Swiper components support lazy loading of data (that is, only the visible part and a small amount of data before and after it are loaded for buffering). Other components still load all at once. data.

LazyForEach must create and is only allowed to create one child component in each iteration.

The generated child components must be child components that are allowed to be included in the LazyForEach parent container component.
LazyForEach is allowed to be included in if/else conditional rendering statements, and if/else conditional rendering statements are also allowed to appear in LazyForEach.
The key-value generator must generate a unique value for each data. If the key values ​​are the same, UI components with the same key values ​​will be ignored by the framework and cannot be displayed in the parent container.
LazyForEach must use the DataChangeListener object to update. When the first parameter dataSource uses a state variable, changes in the state variable will not trigger the UI refresh of LazyForEach.
For high-performance rendering, when updating the UI through the onDataChange method of the DataChangeListener object, a different key value needs to be generated to trigger component refresh.
The calling order of the itemGenerator function is not necessarily the same as the data items in the data source. During the development process, do not assume whether the itemGenerator and keyGenerator functions are executed and their execution order. For example, the following example may not work correctly:

LazyForEach(dataSource, 
  item => Text(`${item.i}. item.data.label`),
  item => item.data.id.toString())

5. Example

// Basic implementation of IDataSource to handle data listener
class BasicDataSource implements IDataSource {
  private listeners: DataChangeListener[] = [];

  public totalCount(): number {
    return 0;
  }

  public getData(index: number): any {
    return undefined;
  }

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

  unregisterDataChangeListener(listener: DataChangeListener): void {
    const pos = this.listeners.indexOf(listener);
    if (pos >= 0) {
      console.info('remove listener');
      this.listeners.splice(pos, 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);
    })
  }

  notifyDataMove(from: number, to: number): void {
    this.listeners.forEach(listener => {
      listener.onDataMove(from, to);
    })
  }
}

class MyDataSource extends BasicDataSource {
  private dataArray: string[] = ['/path/image0', '/path/image1', '/path/image2', '/path/image3'];

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

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

  public addData(index: number, data: string): void {
    this.dataArray.splice(index, 0, data);
    this.notifyDataAdd(index);
  }

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

@Entry
@Component
struct MyComponent {
  private data: MyDataSource = new MyDataSource();

  build() {
    List({ space: 3 }) {
      LazyForEach(this.data, (item: string) => {
        ListItem() {
          Row() {
            Image(item).width('30%').height(50)
            Text(item).fontSize(20).margin({ left: 10 })
          }.margin({ left: 10, right: 10 })
        }
        .onClick(() => {
          this.data.pushData('/path/image' + this.data.totalCount());
        })
      }, item => item)
    }
  }
}

Guess you like

Origin blog.csdn.net/weixin_69135651/article/details/132424759