ListView-Leistung

Beispiel herunterladen Das Beispiel herunterladen

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 DataTemplateauszuwählen, speichert DataTemplatedie 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 MyViewCellAzurückgibt) oder MyDataTemplateB (wobei MyDataTemplateB ein ViewCell vom Typ MyViewCellBzurü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 DataTemplateauszuwählen, DataTemplatenach dem Typ des Elements in der Liste zwischengespeichert werden. DataTemplateDaher werden s einmal pro Elementtyp und nicht einmal pro Element instance ausgewählt.

Hinweis

Die RecycleElementAndDataTemplate Zwischenspeicherungsstrategie setzt voraus, dass die DataTemplatevom zurückgegebenen s den Konstruktor verwenden müssen, der DataTemplateSelectorDataTemplate einen Typeakzeptiert.

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 ListViewvorhanden 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 eine IList<T> Auflistung anstelle einer IEnumerable<T> Auflistung, da IEnumerable<T> Auflistungen den zufälligen Zugriff nicht unterstützen.
  • Verwenden Sie die integrierten Zellen (z. B TextCell / SwitchCell . ) statt wann ViewCell immer möglich.
  • Verwenden Sie weniger Elemente. Erwägen Sie beispielsweise die Verwendung einer einzelnen FormattedString Bezeichnung anstelle mehrerer Bezeichnungen.
  • Ersetzen Sie durch ListView ein TableView , 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 ListViewZeilentrennzeichens 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 oder Grid , um die Schachtelung zu reduzieren.
  • Vermeiden Sie bestimmte LayoutOptions andere als Fill (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 übergeordneten ScrollView-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 verwendet ScrollView wurde. Weitere Informationen finden Sie unter Kopf- und Fußzeilen.
  • 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.