Optimisation des performances avec LazyForEach dans HarmonyOS NEXT

La fonctionnalité LazyForEach optimise les performances en itérant sur les données d'une source à la demande et en créant les composants correspondants au fur et à mesure. Lorsqu'il est utilisé dans un conteneur défilant, LazyForEach crée les composants uniquement pour les éléments visibles à l'écran. Dès qu'un élément sort de la zone visible, son composant associé est détruit et recyclé pour réduire l'utilisation de la mémoire.

Cette technique est particulièrement utile dans les scénarios où une liste nécessite un chargement continu de données lors du défilement. Cependant, pour des listes courtes ou des composants statiques comme un Swiper avec peu d'éléments, l'utilisation de LazyForEach peut être superflue et ajouter une complexité inutile. L'implémentation peut sembler légèrement fastidieuse, mais l'amélioration des performances peut justfiier son usage pour des applications exigeant une fluidité maximale.

Syntaxe de base comparée à ForEach

La différence principale réside dans le premier argument de ces fonctions.

  • ForEach attend directement le tableau de données à rendre.
  • LazyForEach requiert une implémentation de l'interface IDataSource, qui agit comme un adaptateur pour la gestion des données.

// Syntaxe de ForEach
ForEach(dataArray: Array<any>, [itemGenerator: (item: any, index: number) => void, keyGenerator: (item: any, index: number) => string])

// Syntaxe de LazyForEach
LazyForEach(dataSource: IDataSource, [itemGenerator: (item: any, index: number) => void, keyGenerator: (item: any, index: number) => string])

Implémentation de l'interface IDataSource

Pour garantir que les modifications apportées aux données, même en profondeur, déclenchent les mises à jour de l'interface utilisateur, il est crucial d'utiliser le décorateur @Observed. Sans lui, les changements de données pourraient ne pas se refléter correctement.


// Pour détecter les changements de données, même imbriqués, utilisez le décorateur @Observed.
@Observed
export class DynamicDataWrapper implements IDataSource {
  private dataItems: Array<any> = [];
  private subscribers: DataChangeListener[] = [];

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

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

  registerDataChangeListener(listener: DataChangeListener): void {
    if (!this.subscribers.includes(listener)) {
      this.subscribers.push(listener);
    }
  }

  unregisterDataChangeListener(listener: DataChangeListener): void {
    const index = this.subscribers.indexOf(listener);
    if (index !== -1) {
      this.subscribers.splice(index, 1);
    }
  }

  // Ajoute un élément et notifie l'ajout
  appendItem(newItem: any): void {
    this.dataItems.push(newItem);
    // Notifie l'ajout du nouvel élément à la fin
    this.notifyItemAdded(this.dataItems.length - 1);
  }

  // Remplace l'ensemble des données et notifie le rechargement complet
  replaceAll(newData: Array<any>): void {
    this.dataItems = newData;
    this.notifyDataReloaded();
  }

  // Notifie tous les écouteurs que l'intégralité des données a été rechargée
  notifyDataReloaded(): void {
    this.subscribers.forEach(listener => listener.onDataReloaded());
  }

  // Notifie qu'un nouvel élément a été ajouté à l'index spécifié
  notifyItemAdded(index: number): void {
    this.subscribers.forEach(listener => listener.onDataAdd(index));
  }

  // Notifie qu'une modification a eu lieu à l'index spécifié, nécessitant la reconstruction du composant
  notifyItemChanged(index: number): void {
    this.subscribers.forEach(listener => listener.onDataChange(index));
  }

  // Notifie qu'un élément a été supprimé à l'index spécifié
  notifyItemRemoved(index: number): void {
    this.subscribers.forEach(listener => listener.onDataDelete(index));
  }

  // Notifie un déplacement d'élément de l'index 'from' vers l'index 'to'
  notifyItemMoved(from: number, to: number): void {
    this.subscribers.forEach(listener => listener.onDataMove(from, to));
  }
}

Mise en œuvre pratique

Voici comment intégrer LazyForEach avec la source de données personnalisée.


@State listAdapter: DynamicDataWrapper = new DynamicDataWrapper();

// Simulation d'une requête API pour récupérer des données
async onPageAppear(): Promise<void> {
  try {
    const apiResponse = await fetchHomeContent();
    // Toutes les opérations sur les données (ajout, suppression, modification) doivent utiliser les méthodes de DynamicDataWrapper
    this.listAdapter.replaceAll(apiResponse.items);
  } catch (error) {
    console.error("Erreur lors de la récupération des données :", error);
  }
}

// Utilisation de LazyForEach avec l'adaptateur de données
LazyForEach(this.listAdapter, (itemData: any) => {
  // Composant pour chaque élément de la liste
  Column() {
    Image(itemData.imageUrl)
      .width('100%')
      .aspectRatio(16/9) // Maintient le ratio d'aspect de l'image
      .objectFit(ImageFit.Cover);
    Text(itemData.title)
      .fontSize(16)
      .padding(8);
  }
}, (itemData: any) => itemData.id.toString()); // Clé unique pour chaque élément

Étiquettes: HarmonyOS NEXT LazyForEach IDataSource Optimisation

Publié le 21 juin à 16h07