Il modo in cui gestisci la gerarchia degli oggetti View
può influire notevolmente sul rendimento della tua app. In questa pagina viene spiegato come valutare se la gerarchia delle visualizzazioni sta rallentando la tua app e offre alcune strategie per risolvere eventuali problemi.
Questa pagina è incentrata sul miglioramento dei layout basati su View
. Per informazioni su come migliorare il rendimento di Jetpack Compose, consulta Rendimento di Jetpack Compose.
Progetta e misura il rendimento
La pipeline di rendering include una fase di misurazione e layout, durante la quale il sistema posiziona in modo appropriato gli elementi pertinenti nella gerarchia della visualizzazione. La parte misura di questa fase determina le dimensioni e i confini degli oggetti View
. La parte layout determina dove posizionare gli oggetti View
sullo schermo.
Entrambe queste fasi della pipeline comportano un piccolo costo per ogni visualizzazione o layout elaborato. Nella maggior parte dei casi, questo costo è minimo e non influisce in modo significativo sulle prestazioni. Tuttavia, i risultati possono essere migliori
quando un'app aggiunge o rimuove oggetti View
, ad esempio quando
un oggetto RecyclerView
li ricicla o li riutilizza. Il costo può essere più elevato anche se un oggetto View
deve essere ridimensionato per soddisfare i relativi vincoli. Ad esempio, se la tua app chiama
SetText()
un oggetto View
che inserisce un a capo nel testo, potrebbe essere necessario ridimensionare View
.
Se casi come questi richiedono troppo tempo, possono impedire il rendering di un frame entro i 16 ms consentiti, il che può causare la perdita di frame e rendere l'animazione discontinua.
Poiché non puoi spostare queste operazioni in un thread di lavoro, l'app deve elaborarle nel thread principale, è meglio ottimizzarle in modo che richiedano il minor tempo possibile.
Gestire layout complessi
I layout Android ti consentono di nidificare gli oggetti UI nella gerarchia di visualizzazioni. Questo nidificazione può anche comportare un costo di layout. Quando l'app elabora un oggetto per il layout, esegue la stessa operazione su tutti gli elementi secondari del layout.
Per un layout complicato, a volte il costo si verifica solo la prima volta che il sistema calcola il layout. Ad esempio, quando l'app ricicla un elemento dell'elenco complesso in un oggetto RecyclerView
, il sistema deve disporre tutti gli oggetti. In un altro esempio, modifiche banali possono
propagare verso l'alto la catena verso l'elemento padre fino a raggiungere un oggetto che non influisce sulle
dimensioni dell'elemento padre.
Un motivo comune per cui il layout richiede molto tempo è quando le gerarchie di oggetti View
sono nidificate l'una nell'altra. Ogni oggetto di layout nidificato aggiunge un costo alla fase di layout. Quanto più piana è la gerarchia, meno tempo richiede il completamento della fase di layout.
Ti consigliamo di utilizzare lo editor di layout per creare un ConstraintLayout
anziché RelativeLayout
o LinearLayout
, in quanto in genere è più efficiente e riduce il nidificazione dei layout. Tuttavia, per i layout semplici
che possono essere creati con
FrameLayout
, consigliamo
di utilizzare FrameLayout
.
Se utilizzi la classe RelativeLayout
, potresti ottenere lo stesso effetto a un costo inferiore utilizzando visualizzazioni LinearLayout
nidificate e non ponderate. Tuttavia, se utilizzi visualizzazioni LinearLayout
ponderate e nidificate, il costo del layout è molto più elevato perché richiede più passaggi di layout, come spiegato nella sezione successiva.
Ti consigliamo inoltre di utilizzare RecyclerView
anziché
ListView
, in quanto può riutilizzare i
layout dei singoli elementi dell'elenco, il che è più efficiente e può migliorare il
rendimento dello scorrimento.
Doppio imposizione fiscale
In genere, il framework esegue la fase di layout o misurazione in un unico passaggio. Tuttavia, in alcuni casi di layout complicati, il framework potrebbe dover eseguire più volte l'iterazione su parti della gerarchia che richiedono più passaggi per la risoluzione prima di posizionare definitivamente gli elementi. La necessità di eseguire più di un'iterazione di layout e misurazione è definita doppia imposizione.
Ad esempio, quando utilizzi il contenitore RelativeLayout
, che ti consente di posizionare
gli oggetti View
rispetto alle posizioni degli altri oggetti View
, il
framework esegue la seguente sequenza:
- Esegue un passaggio di layout e misurazione, durante il quale il framework calcola la posizione e la dimensione di ogni oggetto figlio, in base alla richiesta di ciascun oggetto figlio.
- Utilizza questi dati, tenendo conto dei pesi degli oggetti, per determinare la posizione corretta delle visualizzazioni correlate.
- Esegue un secondo passaggio di layout per finalizzare le posizioni degli oggetti.
- Passa alla fase successiva del processo di rendering.
Più livelli ha la gerarchia delle visualizzazioni, maggiore è il potenziale impatto negativo sul rendimento.
Come accennato in precedenza, ConstraintLayout
è in genere più efficiente rispetto ad altri
layout, ad eccezione di FrameLayout
. È meno incline a più passaggi di layout e, in molti casi, elimina la necessità di nidificare i layout.
Anche i container diversi da RelativeLayout
potrebbero aumentare la doppia tassazione. Per
esempio:
- Una visualizzazione
LinearLayout
può comportare una doppia verifica del layout e della misurazione se la imposti come orizzontale. Un doppio passaggio di layout e misurazione può verificarsi anche in un orientamento verticale se aggiuntimeasureWithLargestChild
, nel qual caso il framework potrebbe dover eseguire un secondo passaggio per risolvere le dimensioni appropriate degli oggetti. GridLayout
consente anche il posizionamento relativo, ma normalmente evita la doppia tassazione mediante la pre-elaborazione delle relazioni di posizionamento tra le viste figlio. Tuttavia, se il layout utilizza pesi o riempimento con la classeGravity
, il vantaggio della preelaborazione viene perso e il framework potrebbe dover eseguire più passaggi se il contenitore è unRelativeLayout
.
Più passaggi di layout e misurazione non rappresentano necessariamente un onere in termini di rendimento. Tuttavia, possono diventare un peso se non sono posizionati nel posto giusto. Fai attenzione alle situazioni in cui si applica una delle seguenti condizioni al tuo contenitore:
- È un elemento radice della gerarchia delle visualizzazioni.
- Sotto è presente una gerarchia di visualizzazione approfondita.
- Esistono molte istanze che riempiono lo schermo, in modo simile agli elementi secondari in un oggetto
ListView
.
Diagnosticare i problemi relativi alla gerarchia delle visualizzazioni
Le prestazioni del layout sono un problema complesso con molti facet. I seguenti strumenti possono aiutarti a identificare i colli di bottiglia delle prestazioni. Alcuni strumenti forniscono informazioni meno definitive, ma possono fornire suggerimenti utili.
Perfetto
Perfetto è uno strumento che fornisce dati sulle prestazioni. Puoi aprire le tracce Android nell'interfaccia utente di Perfetto.
Traccia prof. render. GPU
Lo strumento sul dispositivo Rendering GPU Profile, disponibile su dispositivi con Android 6.0 (livello API 23) e versioni successive, può fornirti informazioni concrete sui colli di bottiglia delle prestazioni. Questo strumento ti consente di vedere il tempo necessario per la fase di misurazione e layout per ogni frame di rendering. Questi dati possono aiutarti a diagnosticare problemi di prestazioni di runtime e a determinare quali problemi di layout e misurazione devi risolvere.
Nella rappresentazione grafica dei dati acquisiti, il rendering della GPU del profilo utilizza il colore blu per rappresentare il tempo di layout. Per maggiori informazioni su come utilizzare questo strumento, consulta Velocità di rendering della GPU del profilo.
Lint
Lo strumento Lint di Android Studio può aiutarti a capire le inefficienze nella gerarchia delle visualizzazioni. Per utilizzare questo strumento, seleziona Analizza > Ispeziona codice, come mostrato nella Figura 1.
Le informazioni su vari elementi di layout vengono visualizzate in Android > Lint > Rendimento. Per visualizzare ulteriori dettagli, fai clic su ogni elemento per espanderlo e visualizzare ulteriori informazioni nel riquadro sul lato destro dello schermo. La Figura 2 mostra un esempio di informazioni espanse.
Se fai clic su un elemento, nel riquadro a destra vengono visualizzati i problemi associati.
Per saperne di più su argomenti e problemi specifici in quest'area, consulta la documentazione su Lint.
Layout Inspector
Lo strumento Layout Inspector di Android Studio fornisce una rappresentazione visiva della gerarchia delle visualizzazioni della tua app. È un buon modo per navigare nella gerarchia della tua app, fornendo una rappresentazione visiva chiara della catena principale di una determinata visualizzazione e consente di ispezionare i layout costruiti dall'app.
Le viste presentate da Layout Inspector possono anche essere utili per identificare problemi di rendimento derivanti dalla doppia imposizione. Inoltre, può aiutarti a identificare catene profonde di layout nidificati o aree di layout con una grande quantità di elementi secondari nidificati, che possono rappresentare una fonte di costi per le prestazioni. In questi casi, le fasi di layout e misurazione possono essere costose e causare problemi di prestazioni.
Per ulteriori informazioni, consulta Eseguire il debug del layout con Layout Inspector e la convalida del layout.
Risolvere i problemi relativi alla gerarchia di visualizzazione
Il concetto fondamentale alla base della risoluzione dei problemi di prestazioni derivanti dalle gerarchie di visualizzazioni può essere difficile da applicare nella pratica. Per evitare che le gerarchie di visualizzazione impongano penalizzazioni sul rendimento, è necessario appianare la gerarchia di visualizzazione e ridurre la doppia tassazione. Questa sezione illustra le strategie per perseguire questi obiettivi.
Rimuovi i layout nidificati ridondanti
ConstraintLayout
è una libreria Jetpack con un gran numero di meccanismi diversi per il posizionamento delle visualizzazioni all'interno del
layout. In questo modo, non è necessario nidificare un ConstaintLayout
e puoi appianare la gerarchia della visualizzazione. In genere è più semplice appianare le gerarchie utilizzando ConstraintLayout
rispetto ad altri tipi di layout.
Gli sviluppatori spesso usano layout nidificati più del necessario. Ad esempio, un
RelativeLayout
container potrebbe contenere un singolo elemento secondario che è anche un
RelativeLayout
container. Questo nidificazione è ridondante e aggiunge costi non necessari alla gerarchia delle visualizzazioni. Lint può segnalare questo problema, riducendo i tempi di debug.
Applica l'unione o l'inclusione
Una causa frequente di layout nidificati ridondanti è il
<include>
tag. Ad esempio, puoi definire un layout riutilizzabile come segue:
<LinearLayout> <!-- some stuff here --> </LinearLayout>
Potresti quindi aggiungere un tag <include>
per aggiungere il seguente elemento al contenitore principale:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="match_parent" android:layout_height="match_parent" android:background="@color/app_bg" android:gravity="center_horizontal"> <include layout="@layout/titlebar"/> <TextView android:layout_width="match_parent" android:layout_height="wrap_content" android:text="@string/hello" android:padding="10dp" /> ... </LinearLayout>
L'inclusione precedente nidifica inutilmente il primo layout all'interno del secondo layout.
Il tag
<merge>
può aiutarti a evitare questo problema. Per informazioni su questo tag, consulta
Utilizzare il tag <merge>.
Adotta un layout più economico
Potresti non essere in grado di modificare lo schema di layout esistente in modo che non contenga layout ridondanti. In alcuni casi, l'unica soluzione potrebbe essere la suddivisione della gerarchia passando a un tipo di layout completamente diverso.
Ad esempio, potresti scoprire che TableLayout
offre la stessa funzionalità di un layout più complesso con molte dipendenze posizionali. La libreria Jetpack
ConstraintLayout
offre funzionalità simili a RelativeLayout
, oltre ad altre funzionalità per aiutarti a creare
layout più piatti ed efficienti.