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 DataTemplate
s. 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 DataTemplate
ListView
DataTemplateSelector
, DataTemplate
les éléments soient mis en cache par le type d’élément de la liste. Par conséquent, DataTemplate
les 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 DataTemplate
s 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é à uneIList<T>
collection au lieu d’uneIEnumerable<T>
collection, carIEnumerable<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 deViewCell
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 unTableView
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
ListView
sé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
ouGrid
contribuez à réduire l’imbrication. - Évitez d’être spécifique
LayoutOptions
autre queFill
(Fill
est le moins cher pour le calcul). - Évitez de placer un
ListView
élément à l’intérieurScrollView
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 parentScrollView
. - 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éeScrollView
pour. Pour plus d’informations, consultez En-têtes et pieds de page.
- Il
- 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.