Freigeben über


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 DataTemplateverwendet 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 DataTemplateElements DataTemplatedie Zwischenspeicherung durch den Typ des Elements in der Liste zwischengespeichert wird. DataTemplateDaher werden s einmal pro Elementtyp und nicht einmal pro Elementinstanz ausgewählt.

Hinweis

Für die RecycleElementAndDataTemplate Zwischenspeicherungsstrategie ist eine Voraussetzung erforderlich, dass die DataTemplatevon 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 eine IList<T> Auflistung anstelle einer IEnumerable<T> Auflistung, da IEnumerable<T> Sammlungen keinen zufälligen Zugriff unterstützen.
  • Verwenden Sie die integrierten Zellen (z. B. wie TextCell / SwitchCell ) statt ViewCell 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 eine 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, wird die Leistung beeinträchtigt.
  • Vermeiden Sie unter Android das Festlegen einer ListViewZeilentrennzeichensichtbarkeit 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 als Fill (Fill ist die billigste zu berechnen).
  • Vermeiden Sie das Platzieren eines ListView Innenbereichs ScrollView aus den folgenden Gründen:
    • Die ListView Implementierung eines eigenen Bildlaufs.
    • Die ListView empfangen keine Gesten, da sie vom übergeordneten Element ScrollViewbehandelt 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 die ScrollView Funktion verwendet wurde. Weitere Informationen finden Sie unter Kopf- und Fußzeilen.
  • 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.