ListView-Leistung
Beim Schreiben mobiler Anwendungen kommt es auf die Leistung an. Benutzer erwarten einen reibungslosen Bildlauf und schnelle Ladezeiten. Wenn Sie die Erwartungen Ihrer Benutzer nicht erfüllen, kosten Sie Bewertungen im Anwendungsspeicher, oder im Fall einer branchenspezifischen Anwendung kosten Sie Ihre organization Zeit und Geld.
Ist Xamarin.FormsListView
eine leistungsstarke Ansicht zum Anzeigen von Daten, weist jedoch einige Einschränkungen auf. Die Scrollleistung kann bei der Verwendung benutzerdefinierter Zellen beeinträchtigt werden, insbesondere wenn sie tief geschachtelte Ansichtshierarchien enthalten oder bestimmte Layouts verwenden, die komplexe Messungen erfordern. Glücklicherweise gibt es Techniken, mit denen Sie eine schlechte Leistung vermeiden können.
Zwischenspeicherungsstrategie
ListViews werden häufig verwendet, um viel mehr Daten anzuzeigen, als auf dem Bildschirm passen. Beispielsweise kann eine Musik-App über eine Bibliothek mit Songs mit Tausenden von Einträgen verfügen. Das Erstellen eines Elements für jeden Eintrag würde wertvollen Speicher verschwenden und eine schlechte Leistung erbringen. Wenn Sie Zeilen ständig erstellen und zerstören, muss die Anwendung Objekte ständig instanziieren und bereinigen, was auch eine schlechte Leistung hätte.
Um Arbeitsspeicher zu sparen, verfügen die nativen ListView
Entsprechungen für jede Plattform über integrierte Funktionen für die Wiederverwendung von Zeilen. Nur die auf dem Bildschirm sichtbaren Zellen werden in den Arbeitsspeicher geladen, und der Inhalt wird in vorhandene Zellen geladen. Dieses Muster verhindert, dass die Anwendung Tausende von Objekten instanziiert, was Zeit und Arbeitsspeicher spart.
Xamarin.Forms ermöglicht ListView
die Wiederverwendung von Zellen über die ListViewCachingStrategy
-Enumeration, die die folgenden Werte aufweist:
public enum ListViewCachingStrategy
{
RetainElement, // the default value
RecycleElement,
RecycleElementAndDataTemplate
}
Hinweis
Die Universelle Windows-Plattform (UWP) ignoriert die Zwischenspeicherungsstrategie, da sie zur Verbesserung der RetainElement
Leistung immer Zwischenspeicherung verwendet. Daher verhält es sich standardmäßig so, als ob die RecycleElement
Zwischenspeicherungsstrategie angewendet wird.
RetainElement
Die RetainElement
Zwischenspeicherungsstrategie gibt an, dass eine ListView
Zelle für jedes Element in der Liste generiert wird, und ist das Standardverhalten ListView
. Es sollte unter folgenden Umständen verwendet werden:
- Jede Zelle verfügt über eine große Anzahl von Bindungen (20-30+).
- Die Zellenvorlage ändert sich häufig.
- Tests zeigen, dass die
RecycleElement
Zwischenspeicherungsstrategie zu einer verringerten Ausführungsgeschwindigkeit führt.
Es ist wichtig, die Konsequenzen der RetainElement
Zwischenspeicherungsstrategie zu erkennen, wenn Sie mit benutzerdefinierten Zellen arbeiten. Jeder Zellinitialisierungscode muss für jede Zellerstellung ausgeführt werden, was mehrere Male pro Sekunde sein kann. In diesem Fall werden Layouttechniken, die auf einer Seite in Ordnung waren, z. B. die Verwendung mehrerer geschachtelter StackLayout
Instanzen, zu Leistungsengpässen, wenn sie in Echtzeit eingerichtet und zerstört werden, während der Benutzer scrollt.
RecycleElement
Die RecycleElement
Zwischenspeicherungsstrategie gibt an, dass versucht wird, den Speicherbedarf und die ListView
Ausführungsgeschwindigkeit durch das Recycling von Listenzellen zu minimieren. Dieser Modus bietet nicht immer eine Leistungsverbesserung, und es sollten Tests durchgeführt werden, um Verbesserungen zu ermitteln. Es ist jedoch die bevorzugte Wahl und sollte unter den folgenden Umständen verwendet werden:
- Jede Zelle hat eine kleine bis mittlere Anzahl von Bindungen.
- Jede Zelle definiert
BindingContext
alle Zelldaten. - Jede Zelle ist weitgehend ähnlich, wobei die Zellenvorlage unverändert ist.
Während der Virtualisierung wird der Bindungskontext für die Zelle aktualisiert, und wenn eine Anwendung diesen Modus verwendet, muss sie sicherstellen, dass Aktualisierungen des Bindungskontexts ordnungsgemäß verarbeitet werden. Alle Daten über die Zelle müssen aus dem Bindungskontext stammen, da sonst Konsistenzfehler auftreten können. Dieses Problem kann vermieden werden, indem Die Datenbindung zum Anzeigen von Zelldaten verwendet wird. Alternativ sollten Zelldaten in der OnBindingContextChanged
Außerkraftsetzung und nicht im Konstruktor der benutzerdefinierten Zelle festgelegt werden, wie im folgenden Codebeispiel veranschaulicht:
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;
}
}
}
Weitere Informationen finden Sie unter Bindungskontextänderungen.
Wenn Zellen unter iOS und Android benutzerdefinierte Renderer verwenden, müssen sie sicherstellen, dass die Benachrichtigung über Eigenschaftenänderungen ordnungsgemäß implementiert ist. Wenn Zellen wiederverwendet werden, ändern sich ihre Eigenschaftswerte, wenn der Bindungskontext auf den einer verfügbaren Zelle aktualisiert wird, wobei PropertyChanged
Ereignisse ausgelöst werden. Weitere Informationen finden Sie unter Anpassen einer ViewCell.
RecycleElement mit einem DataTemplateSelector
Wenn ein ListView
verwendet, DataTemplateSelector
um einen DataTemplate
auszuwählen, speichert DataTemplate
die RecycleElement
Zwischenspeicherungsstrategie s nicht zwischen. Stattdessen wird für jedes Datenelement in der Liste ein DataTemplate
ausgewählt.
Hinweis
Die RecycleElement
Zwischenspeicherungsstrategie verfügt über eine In Xamarin.Forms Version 2.4 eingeführte Voraussetzung, dass, wenn eine DataTemplateSelector
zur Auswahl eines DataTemplate
aufgefordert wird, die jeweils DataTemplate
denselben ViewCell
Typ zurückgeben muss. Wenn z. B. ein ListView
mit einem DataTemplateSelector
zurückgegeben wird, das entweder MyDataTemplateA
zurückgeben kann (wobei MyDataTemplateA
ein ViewCell
vom Typ MyViewCellA
zurückgibt) oder MyDataTemplateB
(wobei MyDataTemplateB
ein ViewCell
vom Typ MyViewCellB
zurückgibt), wenn MyDataTemplateA
zurückgegeben wird, muss es zurückgegeben werden, MyViewCellA
da sonst eine Ausnahme ausgelöst wird.
RecycleElementAndDataTemplate
Die RecycleElementAndDataTemplate
Zwischenspeicherungsstrategie baut auf der RecycleElement
Zwischenspeicherungsstrategie auf, indem zusätzlich sichergestellt wird, dass, wenn ein ListView
verwendet wird DataTemplateSelector
, um einen DataTemplate
auszuwählen, DataTemplate
nach dem Typ des Elements in der Liste zwischengespeichert werden. DataTemplate
Daher werden s einmal pro Elementtyp und nicht einmal pro Element instance ausgewählt.
Hinweis
Die RecycleElementAndDataTemplate
Zwischenspeicherungsstrategie setzt voraus, dass die DataTemplate
vom zurückgegebenen s den Konstruktor verwenden müssen, der DataTemplateSelector
DataTemplate
einen Type
akzeptiert.
Festlegen der Zwischenspeicherungsstrategie
Der ListViewCachingStrategy
Enumerationswert wird mit einer ListView
Konstruktorüberladung angegeben, wie im folgenden Codebeispiel gezeigt:
var listView = new ListView(ListViewCachingStrategy.RecycleElement);
Legen Sie in XAML das CachingStrategy
Attribut wie im folgenden XAML-Code gezeigt fest:
<ListView CachingStrategy="RecycleElement">
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
...
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
Diese Methode hat die gleiche Auswirkung wie das Festlegen des Arguments für die Zwischenspeicherungsstrategie im Konstruktor in C#.
Festlegen der Zwischenspeicherungsstrategie in einer unterklassierten ListView
Das Festlegen des CachingStrategy
-Attributs aus XAML für eine unterklassierte ListView
Klasse erzeugt nicht das gewünschte Verhalten, da keine CachingStrategy
-Eigenschaft für ListView
vorhanden ist. Wenn XAMLC aktiviert ist, wird außerdem die folgende Fehlermeldung generiert: Keine Eigenschaft, bindbare Eigenschaft oder Ereignis für "CachingStrategy" gefunden
Die Lösung für dieses Problem besteht darin, einen Konstruktor für die untere Klasse ListView
anzugeben, der einen ListViewCachingStrategy
Parameter akzeptiert und an die Basisklasse übergibt:
public class CustomListView : ListView
{
public CustomListView (ListViewCachingStrategy strategy) : base (strategy)
{
}
...
}
Anschließend kann der ListViewCachingStrategy
Enumerationswert aus XAML mithilfe der x:Arguments
Syntax angegeben werden:
<local:CustomListView>
<x:Arguments>
<ListViewCachingStrategy>RecycleElement</ListViewCachingStrategy>
</x:Arguments>
</local:CustomListView>
ListView-Leistungsvorschläge
Es gibt viele Techniken zum Verbessern der Leistung von ListView
. Die folgenden Vorschläge können die Leistung Ihrer ListView verbessern.
- Binden Sie die
ItemsSource
-Eigenschaft an eineIList<T>
Auflistung anstelle einerIEnumerable<T>
Auflistung, daIEnumerable<T>
Auflistungen den zufälligen Zugriff nicht unterstützen. - Verwenden Sie die integrierten Zellen (z. B
TextCell
/SwitchCell
. ) statt wannViewCell
immer möglich. - Verwenden Sie weniger Elemente. Erwägen Sie beispielsweise die Verwendung einer einzelnen
FormattedString
Bezeichnung anstelle mehrerer Bezeichnungen. - Ersetzen Sie durch
ListView
einTableView
, wenn nicht homogene Daten angezeigt werden, d. h. Daten unterschiedlicher Typen. - Beschränken Sie die Verwendung der
Cell.ForceUpdateSize
-Methode. Wenn sie überlastet ist, beeinträchtigt dies die Leistung. - Unter Android sollten Sie vermeiden, die Sichtbarkeit oder Farbe eines
ListView
Zeilentrennzeichens festzulegen, nachdem es instanziiert wurde, da dies zu einer hohen Leistungseinbuße führt. - Vermeiden Sie das Ändern des Zellenlayouts basierend auf
BindingContext
. Das Ändern des Layouts verursacht hohe Mess- und Initialisierungskosten. - Vermeiden Sie tief verschachtelte Layouthierarchien. Verwenden Sie
AbsoluteLayout
oderGrid
, um die Schachtelung zu reduzieren. - Vermeiden Sie bestimmte
LayoutOptions
andere alsFill
(Fill
ist die billigste Compute-Lösung). - Vermeiden Sie aus den folgenden Gründen, eine in einem
ScrollView
zu platzierenListView
:- Der
ListView
implementiert einen eigenen Bildlauf. - Die
ListView
empfängt keine Gesten, da sie vom übergeordnetenScrollView
-Element behandelt werden. - Kann
ListView
eine angepasste Kopf- und Fußzeile darstellen, die mit den Elementen der Liste scrollt und möglicherweise die Funktionalität bietet, für die verwendetScrollView
wurde. Weitere Informationen finden Sie unter Kopf- und Fußzeilen.
- Der
- Ziehen Sie einen benutzerdefinierten Renderer in Betracht, wenn Sie einen bestimmten, komplexen Entwurf benötigen, der in Ihren Zellen dargestellt wird.
AbsoluteLayout
hat das Potenzial, Layouts ohne einen einzelnen Measureaufruf auszuführen, sodass er sehr leistungsfähig ist. Wenn AbsoluteLayout
nicht verwendet werden kann, sollten Sie berücksichtigen RelativeLayout
. Wenn Sie verwenden RelativeLayout
, ist das direkte Übergeben von Einschränkungen wesentlich schneller als die Verwendung der Ausdrucks-API. Diese Methode ist schneller, da die Ausdrucks-API JIT verwendet, und unter iOS muss die Struktur interpretiert werden, was langsamer ist. Die Ausdrucks-API eignet sich für Seitenlayouts, bei denen sie nur für das anfängliche Layout und die Drehung erforderlich ist, aber in ListView
, wo sie während des Bildlaufs ständig ausgeführt wird, beeinträchtigt sie die Leistung.
Das Erstellen eines benutzerdefinierten Renderers für einen ListView
oder seine Zellen ist ein Ansatz, um die Auswirkungen von Layoutberechnungen auf die Bildlaufleistung zu verringern. Weitere Informationen finden Sie unter Anpassen einer ListView und Anpassen einer ViewCell.