ListView-Leistung
Beim Schreiben mobiler Anwendungen ist die Leistung wichtig. Die Benutzer erwarten einen reibungslosen Bildlauf und schnelle Ladezeiten. Wenn Sie die Erwartungen Ihrer Benutzer nicht erfüllen, kosten Sie Bewertungen im Anwendungsspeicher oder im Falle einer Branchenanwendung, kosten Ihre Organisation Zeit und Geld.
Dies Xamarin.FormsListView
ist eine leistungsstarke Ansicht zum Anzeigen von Daten, hat jedoch einige Einschränkungen. Die Bildlaufleistung kann bei der Verwendung benutzerdefinierter Zellen leiden, insbesondere wenn diese tief geschachtelte Ansichtshierarchien enthalten oder bestimmte Layouts verwenden, die komplexe Messungen erfordern. Zum Glück gibt es Techniken, mit denen Sie schlechte Leistungen vermeiden können.
Zwischenspeicherungsstrategie
ListViews werden häufig verwendet, um viel mehr Daten anzuzeigen, als auf dem Bildschirm passt. Eine Musik-App kann zum Beispiel eine Bibliothek mit tausenden Einträgen haben. Die Erstellung eines Elements für jeden Eintrag würde wertvollen Speicherplatz verschwenden und die Leistung beeinträchtigen. Das Erstellen und Zerstören von Zeilen würde die Anwendung dazu benötigen, Objekte ständig zu instanziieren und zu bereinigen, was auch schlecht ausgeführt würde.
Um Speicher zu sparen, haben die nativen ListView
-Äquivalente für jede Plattform integrierte Funktionen zur Wiederverwendung von Zeilen. Nur die auf dem Bildschirm sichtbaren Zellen werden im Arbeitsspeicher geladen, und der Inhalt wird in vorhandene Zellen geladen. Dieses Muster verhindert, dass die Anwendung Tausende von Objekten instanziiert und Zeit und Arbeitsspeicher spart.
Xamarin.Forms ermöglicht ListView
die Wiederverwendung der Zelle ü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 die Zwischenspeicherung immer verwendet wird, um die RetainElement
Leistung zu verbessern. Daher verhält es sich standardmäßig so, als ob die RecycleElement
Zwischenspeicherungsstrategie angewendet wird.
RetainElement
Die RetainElement
-Zwischenspeicherstrategie legt fest, dass ListView
eine Zelle für jedes Element in der Liste erzeugt, und ist das ListView
-Standardverhalten. Es sollte in den folgenden Fällen verwendet werden:
- Jede Zelle hat eine große Anzahl von Bindungen (20–30+).
- Die Zellvorlage ändert sich häufig.
- Die Tests zeigen, dass die
RecycleElement
-Zwischenspeicherstrategie zu einer geringeren Ausführungsgeschwindigkeit führt.
Bei der Arbeit mit benutzerdefinierten Zellen ist es wichtig, die Konsequenzen der RetainElement
-Caching-Strategie zu kennen. Jeder Zelleninitialisierungscode muss bei jeder Zellenerstellung ausgeführt werden, was mehrere Male pro Sekunde der Fall sein kann. In diesem Fall werden Layouttechniken, die auf einer Seite einwandfrei 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
-Zwischenspeicherstrategie legt fest, dass ListView
versucht, seinen Speicherplatzbedarf und seine Ausführungsgeschwindigkeit durch Wiederverwendung von Listenzellen zu minimieren. Dieser Modus bietet nicht immer eine Leistungsverbesserung, und es sollten Tests durchgeführt werden, um etwaige Verbesserungen festzustellen. Sie ist jedoch die bevorzugte Wahl und sollte unter den folgenden Umständen verwendet werden:
- Jede Zelle hat eine kleine bis mittlere Anzahl von Bindungen.
- Der Wert
BindingContext
jeder Zelle definiert alle Daten der Zelle. - Jede Zelle ist weitgehend ähnlich, wobei sich die Zellvorlage nicht ändert.
Während der Virtualisierung wird der Bindungskontext aktualisiert, und wenn eine Anwendung diesen Modus verwendet, muss sichergestellt werden, dass Bindungskontextaktualisierungen ordnungsgemäß verarbeitet werden. Alle Daten über die Zelle müssen aus dem Bindungskontext stammen, sonst können Konsistenzfehler auftreten. Dieses Problem kann durch die Verwendung von Datenbindung zur Anzeige von Zelldaten vermieden werden. 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 Binding Context Changes.
Wenn Zellen benutzerdefinierte Renderer verwenden, müssen sie unter iOS und Android sicherstellen, dass die Eigenschaftsänderungsbenachrichtigung ordnungsgemäß implementiert ist. Wenn Zellen wiederverwendet werden, ändern sich ihre Eigenschaftswerte, wenn der Bindungskontext auf die 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 eine zum Auswählen einer ListView
DataTemplateSelector
Zwischenspeicherungsstrategie DataTemplate
verwendet wird, RecycleElement
werden keine Zwischenspeicherungsstrategien zwischengespeichert DataTemplate
. Stattdessen wird für jedes Datenelement in der Liste ein DataTemplate
ausgewählt.
Hinweis
Die RecycleElement
Zwischenspeicherungsstrategie hat eine Voraussetzung, die in Xamarin.Forms 2.4 eingeführt wurde, dass, wenn ein DataTemplateSelector
Benutzer aufgefordert wird, einen DataTemplate
auszuwählen, der jeweils DataTemplate
denselben ViewCell
Typ zurückgeben muss. Wenn beispielsweise ein ListView
mit einem DataTemplateSelector
entweder MyDataTemplateA
(wobei MyDataTemplateA
ein ViewCell
des Typs MyViewCellA
zurückgibt) oder MyDataTemplateB
(wobei MyDataTemplateB
ein ViewCell
des Typs MyViewCellB
zurückgibt) zurückgegeben wird, muss MyDataTemplateA
MyViewCellA
zurückgeben, sonst wird eine Ausnahme ausgelöst.
RecycleElementAndDataTemplate
Die RecycleElementAndDataTemplate
Zwischenspeicherungsstrategie baut auf der RecycleElement
Zwischenspeicherungsstrategie auf, indem zusätzlich sichergestellt wird, dass bei Verwendung einer DataTemplateSelector
zum Auswählen eines ListView
DataTemplate
Elements DataTemplate
die Zwischenspeicherung durch den Typ des Elements in der Liste zwischengespeichert wird. DataTemplate
Daher werden s einmal pro Elementtyp und nicht einmal pro Elementinstanz ausgewählt.
Hinweis
Für die RecycleElementAndDataTemplate
Zwischenspeicherungsstrategie ist eine Voraussetzung erforderlich, dass die DataTemplate
von dem DataTemplateSelector
Konstruktor zurückgegebenen Werte verwendet werden müssen, die DataTemplate
einen Type
.
Die Zwischenspeicherstrategie festlegen
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 dargestellt fest:
<ListView CachingStrategy="RecycleElement">
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
...
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
Diese Methode hat dieselbe Auswirkung wie das Festlegen des Cachestrategiearguments im Konstruktor in C#.
Festlegen der Zwischenspeicherstrategie in einer unterklassifizierten ListView
Das Setzen des CachingStrategy
-Attributs von XAML auf ein untergeordnetes ListView
führt nicht zum gewünschten Verhalten, da es keine CachingStrategy
-Eigenschaft auf ListView
gibt. Wenn XAMLC aktiviert ist, wird außerdem die folgende Fehlermeldung erzeugt: Keine Eigenschaft, bindungsfähige Eigenschaft oder ereignis für 'CachingStrategy' gefunden.
Die Lösung für dieses Problem besteht darin, einen Konstruktor in der Unterklasse 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 Enumerationswert mithilfe der ListViewCachingStrategy
x:Arguments
Syntax aus XAML angegeben werden:
<local:CustomListView>
<x:Arguments>
<ListViewCachingStrategy>RecycleElement</ListViewCachingStrategy>
</x:Arguments>
</local:CustomListView>
ListView-Leistungsvorschläge
Es gibt viele Techniken zur Verbesserung der Leistung einer .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>
Sammlungen keinen zufälligen Zugriff unterstützen. - Verwenden Sie die integrierten Zellen (z. B. wie
TextCell
/SwitchCell
) stattViewCell
wann immer möglich. - Verwenden Sie weniger Elemente. Ziehen Sie z. B. die Verwendung einer einzelnen
FormattedString
Bezeichnung anstelle mehrerer Bezeichnungen in Betracht. - Ersetzen Sie dies
ListView
durch eineTableView
, wenn nicht homogene Daten angezeigt werden , d. h. Daten unterschiedlicher Typen. - Beschränken Sie die Verwendung der
Cell.ForceUpdateSize
Methode. Wenn sie überlastet ist, wird die Leistung beeinträchtigt. - Vermeiden Sie unter Android das Festlegen einer
ListView
Zeilentrennzeichensichtbarkeit oder -farbe, nachdem sie instanziiert wurde, da dies zu einer hohen Leistungseinbuße führt. - Vermeiden Sie das Ändern des Zellenlayouts basierend auf dem
BindingContext
. Das Ändern des Layouts verursacht große Mess- und Initialisierungskosten. - Vermeiden Sie tief geschachtelte Layouthierarchien. Verwenden oder
AbsoluteLayout
Grid
reduzieren Sie die Schachtelung. - Vermeiden Sie eine andere
LayoutOptions
alsFill
(Fill
ist die billigste zu berechnen). - Vermeiden Sie das Platzieren eines
ListView
InnenbereichsScrollView
aus den folgenden Gründen:- Die
ListView
Implementierung eines eigenen Bildlaufs. - Die
ListView
empfangen keine Gesten, da sie vom übergeordneten ElementScrollView
behandelt werden. - Dies
ListView
kann eine angepasste Kopf- und Fußzeile darstellen, die mit den Elementen der Liste scrollt, was möglicherweise die Funktionalität bietet, für die dieScrollView
Funktion verwendet wurde. Weitere Informationen finden Sie unter Kopf- und Fußzeilen.
- Die
- Ziehen Sie einen benutzerdefinierten Renderer in Betracht, wenn Sie ein bestimmtes, komplexes Design benötigen, das in Ihren Zellen dargestellt wird.
AbsoluteLayout
hat das Potenzial, Layouts ohne einen einzelnen Measureaufruf durchzuführen, was es sehr leistungsfähig macht. Wenn AbsoluteLayout
nicht verwendet werden kann, erwägen Sie RelativeLayout
. Wenn Sie Einschränkungen direkt verwenden RelativeLayout
, ist dies wesentlich schneller als die Verwendung der Ausdrucks-API. Diese Methode ist schneller, da die Ausdrucks-API JIT verwendet, und für 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 sind, 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 eine ListView
oder seine Zellen ist ein Ansatz zur Verringerung der Auswirkungen von Layoutberechnungen auf die Bildlaufleistung. Weitere Informationen finden Sie unter Anpassen einer ListView und Anpassen einer ViewCell.