Partager via


Performances de ListView

Lors de l’écriture d’applications mobiles, les performances sont importantes. Les utilisateurs s’attendent à ce que le défilement lisse et les temps de chargement rapides. L’échec de la réponse aux attentes de vos utilisateurs vous coûtera des évaluations dans le magasin d’applications, ou dans le cas d’une application métier, coûtez le temps et l’argent de votre organisation.

Il Xamarin.FormsListView s’agit d’une vue puissante pour l’affichage des données, mais elle présente certaines limitations. Les performances de défilement peuvent souffrir lors de l’utilisation de cellules personnalisées, en particulier lorsqu’elles contiennent des hiérarchies d’affichage profondément imbriquées ou utilisent certaines dispositions qui nécessitent une mesure complexe. Heureusement, certains techniques vous permettent d’éviter les problèmes de performance.

Stratégie de mise en cache

Les ListViews sont souvent utilisés pour afficher beaucoup plus de données qu’à l’écran. Par exemple, une application musicale peut avoir une bibliothèque de chansons avec des milliers d’entrées. La création d’un élément pour chaque entrée gaspille une mémoire précieuse et fonctionne mal. La création et la destruction de lignes nécessitent constamment que l’application instancie et nettoie constamment les objets, ce qui fonctionne également mal.

Pour conserver la mémoire, les équivalents ListView natifs de chaque plateforme ont des fonctionnalités intégrées pour réutiliser les lignes. Seules les cellules visibles à l’écran sont chargées en mémoire et le contenu est chargé dans des cellules existantes. Ce modèle empêche l’application d’instancier des milliers d’objets, d’économiser du temps et de la mémoire.

Xamarin.FormsListView autorise la réutilisation des cellules par le biais de l’énumérationListViewCachingStrategy, qui a les valeurs suivantes :

public enum ListViewCachingStrategy
{
    RetainElement,   // the default value
    RecycleElement,
    RecycleElementAndDataTemplate
}

Remarque

La plateforme Windows universelle (UWP) ignore la stratégie de mise en cache, car elle utilise toujours la RetainElement mise en cache pour améliorer les performances. Par conséquent, par défaut, il se comporte comme si la RecycleElement stratégie de mise en cache est appliquée.

RetainElement

La stratégie de mise en cache RetainElement spécifie que la cellule ListView génère une cellule pour chaque élément de la liste. Il s’agit du comportement par défaut ListView. Il doit être utilisé dans les circonstances suivantes :

  • Chaque cellule a un grand nombre de liaisons (de 20 à + de 30).
  • Le modèle de cellule change fréquemment.
  • Les tests révèlent que la stratégie de mise en cache RecycleElement entraîne une vitesse d’exécution réduite.

Il est important de reconnaître les conséquences de la stratégie de mise en cache RetainElement lors de l’utilisation de cellules personnalisées. Tout code d’initialisation de cellule doit s’exécuter pour chaque création de cellule, qui peut être de plusieurs fois par seconde. Dans ce cas, les techniques de disposition qui étaient correctes sur une page, comme l’utilisation de plusieurs instances imbriquées StackLayout , deviennent des goulots d’étranglement des performances lorsqu’elles sont configurées et détruites en temps réel lorsque l’utilisateur défile.

RecycleElement

La stratégie de mise en cache RecycleElement spécifie que le ListView va tenter de réduire son empreinte mémoire et sa vitesse d’exécution en recyclant les cellules de la liste de recyclage. Ce mode n’offre pas toujours d’amélioration des performances. Vous devez mener des tests pour déterminer les améliorations. Toutefois, il s’agit du choix privilégié, qui doit être utilisé dans les circonstances suivantes :

  • Chaque cellule a un petit nombre modéré de liaisons.
  • Le BindingContext de chaque cellule définit toutes les données de cellule.
  • Chaque cellule est très similaire, le modèle de cellule étant le même.

Pendant la virtualisation, la cellule aura son contexte de liaison mis à jour. Par conséquent, si une application utilise ce mode, elle doit s’assurer que les mises à jour du contexte de liaison sont gérées de manière appropriée. Toutes les données relatives à la cellule doivent provenir du contexte de liaison, sous peine d’erreurs de cohérence. Ce problème peut être évité en utilisant la liaison de données pour afficher les données de cellule. Vous pouvez également définir les données de cellule dans le OnBindingContextChanged remplacement, plutôt que dans le constructeur de la cellule personnalisée, comme illustré dans l’exemple de code suivant :

public class CustomCell : ViewCell
{
    Image image = null;
    
    public CustomCell ()
    {
        image = new Image();
        View = image;
    }
    
    protected override void OnBindingContextChanged ()
    {
        base.OnBindingContextChanged ();
        
        var item = BindingContext as ImageItem;
        if (item != null) {
            image.Source = item.ImageUrl;
        }
    }
}

Pour plus d’informations, consultez Modifications du contexte de liaison.

Sur iOS et Android, si les cellules utilisent des renderers personnalisés, elles doivent s’assurer que la notification de modification de propriété est correctement implémentée. Lorsque les cellules sont réutilisées, leurs valeurs de propriété changent lorsque le contexte de liaison est mis à jour vers celle d’une cellule disponible, avec PropertyChanged des événements déclenchés. Pour plus d’informations, consultez Personnalisation d’un ViewCell.

RecycleElement avec un DataTemplateSelector

Lorsqu’un ListView utilise un DataTemplateSelector pour sélectionner un DataTemplate, la RecycleElement stratégie de mise en cache ne met pas en cache DataTemplates. Au lieu de cela, un DataTemplate est sélectionné pour chaque élément de données de la liste.

Remarque

La RecycleElement stratégie de mise en cache présente une condition préalable, introduite dans Xamarin.Forms la version 2.4, que lorsqu’une DataTemplateSelector stratégie de mise en cache est demandée, DataTemplate chacune DataTemplate doit retourner le même ViewCell type. Prenons l’exemple d’un ListView avec un DataTemplateSelector pouvant retourner MyDataTemplateA (où MyDataTemplateA retourne un ViewCell de type MyViewCellA) ou MyDataTemplateB (où MyDataTemplateB retourne un ViewCell de type MyViewCellB), lorsque MyDataTemplateA est retourné, il doit retourner MyViewCellA, sous peine de générer une exception.

RecycleElementAndDataTemplate

La RecycleElementAndDataTemplate stratégie de mise en cache s’appuie sur la RecycleElement stratégie de mise en cache en veillant également à ce qu’en cas d’utilisation d’un DataTemplateListView DataTemplateSelector , DataTemplateles éléments soient mis en cache par le type d’élément de la liste. Par conséquent, DataTemplateles s sont sélectionnés une fois par type d’élément, au lieu d’une fois par instance d’élément.

Remarque

La RecycleElementAndDataTemplate stratégie de mise en cache présente une condition préalable à laquelle les DataTemplates retournés par le DataTemplateSelector constructeur doivent utiliser le DataTemplate constructeur qui accepte un Type.

Définir la stratégie de mise en cache

La ListViewCachingStrategy valeur d’énumération est spécifiée avec une ListView surcharge de constructeur, comme illustré dans l’exemple de code suivant :

var listView = new ListView(ListViewCachingStrategy.RecycleElement);

En XAML, définissez l’attribut CachingStrategy comme indiqué dans le code XAML ci-dessous :

<ListView CachingStrategy="RecycleElement">
    <ListView.ItemTemplate>
        <DataTemplate>
            <ViewCell>
              ...
            </ViewCell>
        </DataTemplate>
    </ListView.ItemTemplate>
</ListView>

Cette méthode a le même effet que la définition de l’argument de stratégie de mise en cache dans le constructeur en C#.

Définir la stratégie de mise en cache dans un ListView sous-classé

La définition de l’attribut CachingStrategy à partir de XAML sur un ListView sous-classé ne produit pas le comportement souhaité, car il n’y a pas de propriété CachingStrategy sur ListView. En outre, si XAMLC est activé, le message d’erreur suivant est généré : Aucune propriété, propriété pouvant être liée ou événement trouvé pour « CachingStrategy »

La solution à ce problème consiste à spécifier un constructeur sur la sous-classe ListView qui accepte un ListViewCachingStrategy paramètre et le transmet à la classe de base :

public class CustomListView : ListView
{
    public CustomListView (ListViewCachingStrategy strategy) : base (strategy)
    {
    }
    ...
}

Ensuite, la ListViewCachingStrategy valeur d’énumération peut être spécifiée à partir du code XAML à l’aide de la x:Arguments syntaxe :

<local:CustomListView>
    <x:Arguments>
        <ListViewCachingStrategy>RecycleElement</ListViewCachingStrategy>
    </x:Arguments>
</local:CustomListView>

Suggestions de performances ListView

Il existe de nombreuses techniques pour améliorer les performances d’un ListView. Les suggestions suivantes peuvent améliorer les performances de votre ListView

  • Liez la ItemsSource propriété à une IList<T> collection au lieu d’une IEnumerable<T> collection, car IEnumerable<T> les collections ne prennent pas en charge l’accès aléatoire.
  • Utilisez les cellules intégrées (par exemple TextCell / SwitchCell ) au lieu de ViewCell chaque fois que vous le pouvez.
  • Utilisez moins d’éléments. Par exemple, envisagez d’utiliser une seule FormattedString étiquette au lieu de plusieurs étiquettes.
  • Remplacez l’élément ListView par un TableView lors de l’affichage de données non homogènes, c’est-à-dire des données de différents types.
  • Limitez l’utilisation de la Cell.ForceUpdateSize méthode. Si elle est surutilisée, elle dégrade les performances.
  • Sur Android, évitez de définir la visibilité ou la couleur d’un ListViewséparateur de lignes après son instanciation, car elle entraîne une pénalité de performances importante.
  • Évitez de modifier la disposition des cellules en fonction du BindingContext. La modification de la disposition entraîne des coûts de mesure et d’initialisation importants.
  • Évitez les hiérarchies de disposition profondément imbriquées. Utilisez AbsoluteLayout ou Grid contribuez à réduire l’imbrication.
  • Évitez d’être spécifique LayoutOptions autre que Fill (Fill est le moins cher pour le calcul).
  • Évitez de placer un ListView élément à l’intérieur ScrollView pour les raisons suivantes :
    • Il ListView implémente son propre défilement.
    • Les ListView mouvements ne seront pas reçus, car ils seront gérés par le parent ScrollView.
    • Il ListView peut présenter un en-tête et un pied de page personnalisés qui défilent avec les éléments de la liste, offrant potentiellement la fonctionnalité utilisée ScrollView pour. Pour plus d’informations, consultez En-têtes et pieds de page.
  • Considérez un renderer personnalisé si vous avez besoin d’une conception spécifique et complexe présentée dans vos cellules.

AbsoluteLayout a le potentiel d’effectuer des dispositions sans appel de mesure unique, ce qui en fait très performant. Si AbsoluteLayout vous ne pouvez pas l’utiliser, envisagez RelativeLayout. Si vous utilisez RelativeLayout, la transmission directe de contraintes sera considérablement plus rapide que l’utilisation de l’API d’expression. Cette méthode est plus rapide, car l’API d’expression utilise JIT et, sur iOS, l’arborescence doit être interprétée, ce qui est plus lent. L’API d’expression convient aux mises en page où elle n’est requise que lors de la mise en page initiale et de la rotation, mais dans ListView, où elle est exécutée constamment pendant le défilement, elle nuit aux performances.

La création d’un renderer personnalisé pour une ListView ou ses cellules est une approche pour réduire l’effet des calculs de disposition sur les performances de défilement. Pour plus d’informations, consultez Personnalisation d’un ListView et Personnalisation d’un ViewCell.