Share via


Prestazioni di ListView

Quando si scrivono applicazioni per dispositivi mobili, le prestazioni sono importanti. Gli utenti si aspettano tempi di scorrimento e caricamento rapidi. Se non si soddisfano le aspettative degli utenti, si costeranno valutazioni nell'archivio applicazioni o nel caso di un'applicazione line-of-business, costare tempo e denaro per l'organizzazione.

è Xamarin.FormsListView una visualizzazione potente per la visualizzazione dei dati, ma presenta alcune limitazioni. Le prestazioni di scorrimento possono risentire quando si usano celle personalizzate, soprattutto quando contengono gerarchie di visualizzazione annidate in profondità o si usano determinati layout che richiedono una misurazione complessa. Fortunatamente, esistono tecniche che è possibile usare per evitare prestazioni scarse.

Strategia di memorizzazione nella cache

Le visualizzazioni ListView vengono spesso usate per visualizzare molti più dati rispetto a quelli visualizzati sullo schermo. Ad esempio, un'app musicale potrebbe avere una libreria di canzoni con migliaia di voci. La creazione di un elemento per ogni voce potrebbe sprecare memoria preziosa e prestazioni scarse. La creazione e l'eliminazione costante di righe richiederebbero all'applicazione di creare istanza e pulire gli oggetti in modo costante, con prestazioni anche scarse.

Per risparmiare memoria, gli equivalenti nativi ListView per ogni piattaforma hanno funzionalità predefinite per il riutilizzo delle righe. Solo le celle visibili sullo schermo vengono caricate in memoria e il contenuto viene caricato nelle celle esistenti. Questo modello impedisce all'applicazione di creare un'istanza di migliaia di oggetti, risparmiando tempo e memoria.

Xamarin.Forms consente il ListView riutilizzo delle celle tramite l'enumerazione ListViewCachingStrategy , con i valori seguenti:

public enum ListViewCachingStrategy
{
    RetainElement,   // the default value
    RecycleElement,
    RecycleElementAndDataTemplate
}

Nota

La piattaforma UWP (Universal Windows Platform) (UWP) ignora la strategia di memorizzazione nella cache, perché usa sempre la RetainElement memorizzazione nella cache per migliorare le prestazioni. Pertanto, per impostazione predefinita, si comporta come se fosse applicata la RecycleElement strategia di memorizzazione nella cache.

RetainElement

La RetainElement strategia di memorizzazione nella cache specifica che ListView genererà una cella per ogni elemento nell'elenco ed è il comportamento predefinito ListView . Deve essere usato nelle circostanze seguenti:

  • Ogni cella ha un numero elevato di associazioni (20-30+).
  • Il modello di cella cambia frequentemente.
  • Il test rivela che la strategia di RecycleElement memorizzazione nella cache comporta una riduzione della velocità di esecuzione.

È importante riconoscere le conseguenze della strategia di RetainElement memorizzazione nella cache quando si lavora con celle personalizzate. Qualsiasi codice di inizializzazione delle celle dovrà essere eseguito per ogni creazione di cella, che può essere più volte al secondo. In questa circostanza, le tecniche di layout eseguite correttamente in una pagina, come l'uso di più istanze annidate StackLayout , diventano colli di bottiglia delle prestazioni quando vengono configurati e eliminati definitivamente in tempo reale mentre l'utente scorre.

RecycleElement

La RecycleElement strategia di memorizzazione nella cache specifica che ListView tenterà di ridurre al minimo il footprint di memoria e la velocità di esecuzione riciclando le celle dell'elenco. Questa modalità non offre sempre un miglioramento delle prestazioni e i test devono essere eseguiti per determinare eventuali miglioramenti. Tuttavia, è la scelta preferita e deve essere usata nelle circostanze seguenti:

  • Ogni cella ha un numero ridotto o moderato di associazioni.
  • Ogni cella BindingContext definisce tutti i dati delle celle.
  • Ogni cella è in gran parte simile, con il modello di cella che non cambia.

Durante la virtualizzazione la cella avrà aggiornato il contesto di associazione e pertanto, se un'applicazione usa questa modalità, deve assicurarsi che gli aggiornamenti del contesto di associazione vengano gestiti in modo appropriato. Tutti i dati relativi alla cella devono provenire dal contesto di associazione o possono verificarsi errori di coerenza. Questo problema può essere evitato usando il data binding per visualizzare i dati delle celle. In alternativa, i dati delle celle devono essere impostati nell'override OnBindingContextChanged , anziché nel costruttore della cella personalizzata, come illustrato nell'esempio di codice seguente:

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;
        }
    }
}

Per altre informazioni, vedere Binding Context Changes.For more information, see Binding Context Changes.

In iOS e Android, se le celle usano renderer personalizzati, devono assicurarsi che la notifica di modifica delle proprietà sia implementata correttamente. Quando le celle vengono riutilizzate, i valori delle proprietà cambiano quando il contesto di associazione viene aggiornato a quello di una cella disponibile, con PropertyChanged eventi generati. Per altre informazioni, vedere Personalizzazione di un elemento ViewCell.

RecycleElement con DataTemplateSelector

Quando un ListView oggetto usa un DataTemplateSelector oggetto per selezionare un DataTemplateoggetto , la strategia di memorizzazione nella cache non memorizza nella RecycleElement cache DataTemplates. Viene invece selezionato un oggetto DataTemplate per ogni elemento di dati nell'elenco.

Nota

La RecycleElement strategia di memorizzazione nella cache ha un prerequisito, introdotto nella Xamarin.Forms versione 2.4, che quando viene richiesto a un oggetto DataTemplateSelector di selezionare che DataTemplate ognuno DataTemplate deve restituire lo stesso ViewCell tipo. Ad esempio, dato un ListView oggetto con che DataTemplateSelector può restituire MyDataTemplateA (dove MyDataTemplateA restituisce un ViewCell di tipo MyViewCellA) o MyDataTemplateB (dove MyDataTemplateB restituisce un ViewCell di tipo MyViewCellB), quando MyDataTemplateA viene restituito deve restituire MyViewCellA o verrà generata un'eccezione.

RecycleElementAndDataTemplate

La RecycleElementAndDataTemplate strategia di memorizzazione nella cache si basa sulla RecycleElement strategia di memorizzazione nella cache assicurando inoltre che quando un ListView oggetto usa per DataTemplateSelector selezionare un DataTemplateoggetto , DataTemplates viene memorizzato nella cache in base al tipo di elemento nell'elenco. Pertanto, DataTemplates viene selezionato una volta per ogni tipo di elemento, anziché una volta per ogni istanza di elemento.

Nota

La RecycleElementAndDataTemplate strategia di memorizzazione nella cache ha un prerequisito che deve DataTemplateessere DataTemplate utilizzato dal DataTemplateSelector costruttore che accetta un oggetto Type.

Impostare la strategia di memorizzazione nella cache

Il ListViewCachingStrategy valore di enumerazione viene specificato con un ListView overload del costruttore, come illustrato nell'esempio di codice seguente:

var listView = new ListView(ListViewCachingStrategy.RecycleElement);

In XAML impostare l'attributo CachingStrategy come illustrato nel codice XAML seguente:

<ListView CachingStrategy="RecycleElement">
    <ListView.ItemTemplate>
        <DataTemplate>
            <ViewCell>
              ...
            </ViewCell>
        </DataTemplate>
    </ListView.ItemTemplate>
</ListView>

Questo metodo ha lo stesso effetto dell'impostazione dell'argomento strategia di memorizzazione nella cache nel costruttore in C#.

Impostare la strategia di memorizzazione nella cache in un controllo ListView sottoclassato

L'impostazione dell'attributo CachingStrategy da XAML in una sottoclassata ListView non produrrà il comportamento desiderato, perché non esiste alcuna CachingStrategy proprietà in ListView. Inoltre, se XAMLC è abilitato, verrà generato il messaggio di errore seguente: Nessuna proprietà, proprietà associabile o evento trovato per 'CachingStrategy'

La soluzione a questo problema consiste nel specificare un costruttore nella sottoclassata ListView che accetta un ListViewCachingStrategy parametro e lo passa nella classe base:

public class CustomListView : ListView
{
    public CustomListView (ListViewCachingStrategy strategy) : base (strategy)
    {
    }
    ...
}

È quindi possibile specificare il ListViewCachingStrategy valore di enumerazione da XAML usando la x:Arguments sintassi :

<local:CustomListView>
    <x:Arguments>
        <ListViewCachingStrategy>RecycleElement</ListViewCachingStrategy>
    </x:Arguments>
</local:CustomListView>

Suggerimenti sulle prestazioni di ListView

Esistono molte tecniche per migliorare le prestazioni di un oggetto ListView. I suggerimenti seguenti possono migliorare le prestazioni di ListView

  • Associare la ItemsSource proprietà a una IList<T> raccolta anziché a una IEnumerable<T> raccolta, perché IEnumerable<T> le raccolte non supportano l'accesso casuale.
  • Usare le celle predefinite (ad esempio TextCell / SwitchCell ) anziché ViewCell ogni volta che è possibile.
  • Usare un minor numero di elementi. Si consideri ad esempio l'uso di una singola FormattedString etichetta anziché di più etichette.
  • ListView Sostituire con un TableView oggetto quando vengono visualizzati dati non omogenei, ovvero dati di tipi diversi.
  • Limitare l'uso del Cell.ForceUpdateSize metodo . Se sovrautilizzata, le prestazioni risulteranno ridotte.
  • In Android evitare di impostare la visibilità o il colore del separatore di riga di un ListViewoggetto dopo che è stata creata un'istanza, in quanto comporta una riduzione delle prestazioni elevata.
  • Evitare di modificare il layout della cella in base a BindingContext. La modifica del layout comporta grandi costi di misurazione e inizializzazione.
  • Evitare gerarchie di layout annidate in modo approfondito. Usare AbsoluteLayout o Grid per ridurre l'annidamento.
  • Evitare specifiche LayoutOptions diverse da Fill (Fill è la più economica da calcolare).
  • Evitare di inserire un oggetto ListView all'interno di per ScrollView i motivi seguenti:
    • ListView Implementa il proprio scorrimento.
    • L'oggetto ListView non riceverà alcun movimento, perché verrà gestito dall'oggetto padre ScrollView.
    • ListView Può presentare un'intestazione e un piè di pagina personalizzati che scorre con gli elementi dell'elenco, offrendo potenzialmente la funzionalità ScrollView usata da . Per altre informazioni, vedere Intestazioni e piè di pagina.
  • Prendere in considerazione un renderer personalizzato se è necessaria una progettazione specifica e complessa presentata nelle celle.

AbsoluteLayout ha il potenziale di eseguire layout senza una singola chiamata di misura, rendendolo estremamente efficiente. Se AbsoluteLayout non è possibile usare , prendere in considerazione RelativeLayout. Se si usa RelativeLayout, il passaggio diretto dei vincoli sarà notevolmente più veloce rispetto all'uso dell'API dell'espressione. Questo metodo è più veloce perché l'API dell'espressione usa JIT e in iOS l'albero deve essere interpretato, che è più lento. L'API delle espressioni è adatta per i layout di pagina in cui è necessaria solo per il layout iniziale e la rotazione, ma in , dove ListViewviene eseguita costantemente durante lo scorrimento, le prestazioni vengono ridotte.

La creazione di un renderer personalizzato per una ListView o le relative celle è un approccio per ridurre l'effetto dei calcoli di layout sulle prestazioni di scorrimento. Per altre informazioni, vedere Personalizzazione di un controllo ListView e Personalizzazione di un controllo ViewCell.