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, il existe des techniques que vous pouvez utiliser pour éviter de mauvaises performances.

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 propre up objets constamment, ce qui fonctionne également mal.

Pour conserver la mémoire, les équivalents natifs ListView 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 RetainElement stratégie de mise en cache spécifie que la ListView cellule génère une cellule pour chaque élément de la liste et est le comportement par défaut ListView . Il doit être utilisé dans les circonstances suivantes :

  • Chaque cellule a un grand nombre de liaisons (20-30+).
  • Le modèle de cellule change fréquemment.
  • Les tests révèlent que la RecycleElement stratégie de mise en cache 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 lors de l’utilisation RetainElement de cellules personnalisées. Tout code d’initialisation de cellule doit s’exécuter pour chaque création de cellule, qui peut être 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 RecycleElement stratégie de mise en cache spécifie que la ListView stratégie de mise en cache tente de réduire son empreinte mémoire et sa vitesse d’exécution en recyclant les cellules de liste. Ce mode n’offre pas toujours d’amélioration des performances et les tests doivent être effectués pour déterminer les améliorations. Toutefois, il s’agit du choix préféré et doit être utilisé dans les circonstances suivantes :

  • Chaque cellule a un petit nombre modéré de liaisons.
  • Chaque cellule BindingContext définit toutes les données de cellule.
  • Chaque cellule est largement similaire, avec le modèle de cellule qui change.

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 ou des erreurs de cohérence peuvent se produire. Ce problème peut être évité à l’aide de 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 élément de données 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. Par exemple, étant donné un ListView avec un DataTemplateSelector qui peut retourner MyDataTemplateA soit (où MyDataTemplateA retourne un ViewCell type MyViewCellA), soit MyDataTemplateB (où MyDataTemplateB retourne un ViewCell type MyViewCellB), lorsqu’il est retourné, il MyDataTemplateA doit retourner MyViewCellA ou une exception sera levée.

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 DataTemplateListViewDataTemplateSelector , 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 une sous-classe ListView ne produit pas le comportement souhaité, car il n’y a pas CachingStrategy de propriété 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.