Accelerazione hardware

A partire da Android 3.0 (livello API 11), la pipeline di rendering 2D di Android supporta l'hardware accelerazione, cioè tutte le operazioni di disegno che vengono eseguite su Il canvas di View utilizza la GPU. Grazie all'aumento delle risorse necessarie per abilitare l'accelerazione hardware, la tua app consumerà più RAM.

L'accelerazione hardware è abilitata per impostazione predefinita se il livello API target è maggiore di 14, ma può anche esplicitamente abilitato. Se la tua applicazione utilizza solo viste standard e Drawable, l'attivazione globale non dovrebbe causare effetti negativi e gli effetti sonori. Tuttavia, poiché l'accelerazione hardware non è supportata per tutti i disegni 2D operazioni, la sua attivazione potrebbe influire su alcune visualizzazioni personalizzate o chiamate di disegno. Problemi di solito si manifestano come elementi invisibili, eccezioni o pixel visualizzati in modo errato. A Risolvi il problema, Android ti offre la possibilità di attivare o disattivare l'accelerazione hardware in più diversi. Consulta la sezione Controllare l'accelerazione hardware.

Se la tua applicazione esegue un disegno personalizzato, testa l'applicazione su dispositivi hardware reali con l'accelerazione hardware attivata per rilevare eventuali problemi. La sezione Assistenza per le operazioni di disegno descrive i problemi noti relativi alle l'accelerazione hardware e come aggirare le limitazioni.

Vedi anche OpenGL con le API Framework e Renderscript

Controlla l'accelerazione hardware

Puoi controllare l'accelerazione hardware ai seguenti livelli:

  • Applicazione
  • Attività
  • Finestra
  • Visualizza

Livello di applicazione

Nel file manifest Android, aggiungi il seguente attributo alla Tag <application> per abilitare l'accelerazione hardware per l'intera applicazione:

<application android:hardwareAccelerated="true" ...>

Livello attività

Se la tua applicazione non si comporta correttamente con l'accelerazione hardware attivata a livello globale, puoi controllarlo anche per le singole attività. Per attivare o disattivare l'accelerazione hardware su il livello di attività, puoi utilizzare l'attributo android:hardwareAccelerated per <activity>. L'esempio seguente abilita l'accelerazione hardware per l'intera applicazione, ma la disattiva per un'attività:

<application android:hardwareAccelerated="true">
    <activity ... />
    <activity android:hardwareAccelerated="false" />
</application>

A livello di finestra

Se hai bisogno di un controllo ancora più granulare, puoi abilitare l'accelerazione hardware per un determinato con il seguente codice:

Kotlin

window.setFlags(
        WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED,
        WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED
)

Java

getWindow().setFlags(
    WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED,
    WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED);

Nota: al momento non puoi disattivare l'accelerazione hardware in a livello della finestra.

Livello di vista

Puoi disattivare l'accelerazione hardware per una singola vista in fase di runtime con codice seguente:

Kotlin

myView.setLayerType(View.LAYER_TYPE_SOFTWARE, null)

Java

myView.setLayerType(View.LAYER_TYPE_SOFTWARE, null);

Nota: al momento non puoi attivare l'accelerazione hardware in a livello di vista. I livelli vista hanno altre funzioni oltre alla disattivazione dell'accelerazione hardware. Consulta la sezione Visualizza livelli per ulteriori informazioni sul loro utilizzo.

Determinare se una vista è con accelerazione hardware

A volte è utile per un'applicazione sapere se si tratta di hardware attualmente accelerata, in particolare per aspetti come le visualizzazioni personalizzate. Ciò è particolarmente utile se le tue esegue molti disegni personalizzati e non tutte le operazioni sono supportate correttamente dal nuovo pipeline di rendering.

Esistono due modi diversi per verificare se l'applicazione è con accelerazione hardware:

Se devi fare questo controllo nel codice del disegno, usa Canvas.isHardwareAccelerated() invece di View.isHardwareAccelerated() quando possibile. Quando una visualizzazione è collegato a una finestra con accelerazione hardware, può essere disegnato usando ha accelerato Canvas. Ciò accade, ad esempio, quando si disegna una vista in una bitmap per la memorizzazione nella cache. scopi.

Modelli di disegno Android

Quando l'accelerazione hardware è abilitata, il framework Android utilizza un nuovo modello di disegno che utilizza gli elenchi di visualizzazione per eseguire il rendering dell'applicazione sullo schermo. Per comprendere appieno visualizzare elenchi e il modo in cui potrebbero influire sulla tua applicazione, è utile capire in che modo Android traccia le visualizzazioni anche senza accelerazione hardware. Nelle sezioni seguenti vengono descritte le modelli di disegno basati su software e con accelerazione hardware.

Modello di disegno basato su software

Nel modello di disegno software, le viste vengono tracciate con i due passaggi seguenti:

  1. Annullare la validità della gerarchia
  2. Tracciare la gerarchia

Ogni volta che un'applicazione deve aggiornare una parte della sua UI, richiama invalidate() (o una delle sue varianti) su qualsiasi vista modificata contenuti. I messaggi di invalidazione vengono propagati fino alla gerarchia di visualizzazione le aree dello schermo che devono essere ridisegnate (la regione "sporca"). Il sistema Android disegna qualsiasi vista della gerarchia che si interseca con la regione "sporca". Purtroppo, questo modello di disegno presenta due svantaggi:

  • Innanzitutto, questo modello richiede l'esecuzione di una grande quantità di codice a ogni Draw Pass. Ad esempio, se la tua applicazione chiama invalidate() su un pulsante e sopra un'altra visualizzazione, il sistema Android ridisegna la visualizzazione anche se è cambiato.
  • Il secondo problema è che il modello di disegno può nascondere bug nell'applicazione. Poiché il Il sistema Android ridisegna le visualizzazioni quando queste si intersecano con la regione "sporca", una vista di cui modificato potrebbe essere ridisegnato anche se invalidate() non è stato che ha chiamato. In questi casi, ci si affida all'invalidazione di un'altra vista per ottenere comportamento corretto. Questo comportamento può cambiare ogni volta che modifichi l'applicazione. A causa di questa, devi sempre chiamare invalidate() nella tua configurazione viste ogni volta che modifichi dati o stati che influiscono sul codice di disegno della vista.

Nota: le visualizzazioni Android chiamano automaticamente invalidate() quando le loro proprietà cambiano, ad esempio lo sfondo colore o il testo in un TextView.

Modello di disegno con accelerazione hardware

Il sistema Android utilizza ancora invalidate() e draw() per richiedere aggiornamenti dello schermo e per eseguire il rendering delle visualizzazioni, ma gestisce il disegno reale in modo diverso. Anziché eseguire immediatamente i comandi di disegno, Android nel sistema li registra all'interno di elenchi di visualizzazione, che contengono l'output della codice di disegno. Un'altra ottimizzazione è che il sistema Android deve solo registrare e aggiornare mostra elenchi per visualizzazioni contrassegnate come "sporche" da un invalidate() chiamata. Le viste che non sono state invalidate possono essere ridisegnate semplicemente riemettendo la precedente elenco di visualizzazioni registrate. Il nuovo modello di disegno contiene tre fasi:

  1. Annullare la validità della gerarchia
  2. Registrare e aggiornare gli elenchi di visualizzazione
  3. Traccia gli elenchi di visualizzazione

Con questo modello, non puoi fare affidamento su una vista che interseca la regione "sporca" per eseguire il metodo draw(). Per garantire che il sistema Android registri un nell'elenco di visualizzazione, devi chiamare invalidate(). Eliminazione questo fa sì che una vista abbia lo stesso aspetto anche dopo essere stata modificata.

L'uso degli elenchi di visualizzazione va a vantaggio anche delle prestazioni dell'animazione, in quanto impostare proprietà specifiche, come alpha o rotazione, non richiede la convalida della vista target (viene eseguita automaticamente). Questa ottimizzazione si applica anche alle visualizzazioni con elenchi display (qualsiasi visualizzazione quando dell'applicazione è con accelerazione hardware.) Ad esempio, supponiamo che ci sia un LinearLayout che contiene un ListView sopra un Button. L'elenco di visualizzazione di LinearLayout ha questo aspetto questo:

  • DrawDisplayList(ListView)
  • DrawDisplayList(Pulsante)

Supponiamo ora di modificare l'opacità dell'ListView. Dopo il giorno chiamata setAlpha(0.5f) su ListView, ora l'elenco visualizzato contiene:

  • SalvaLivelloAlpha(0,5)
  • DrawDisplayList(ListView)
  • Ripristina
  • DrawDisplayList(Pulsante)

Il codice di disegno complesso di ListView non è stato eseguito. Invece, ha aggiornato solo l'elenco di visualizzazione della versione molto più semplice di LinearLayout. Nella un'applicazione senza accelerazione hardware abilitata, il codice di disegno sia dell'elenco che vengono eseguite di nuovo.

Supporto per le operazioni di disegno

Quando viene eseguita l'accelerazione hardware, la pipeline di rendering 2D supporta i modelli Canvas e molte operazioni meno utilizzate. Tutte le operazioni di disegno utilizzate per il rendering di applicazioni fornite con Android, widget predefiniti e layout, mentre gli effetti visivi avanzati più comuni, come riflessi e texture affiancate, supportati.

La tabella seguente descrive il livello di supporto di varie operazioni nei vari livelli API:

Primo livello API supportato
Tela
drawBitmapMesh() (array colori) 18
drawPicture() 23
drawPosText() 16
drawTextOnPath() 16
drawVertices() 29
setDrawFilter() 16
clipPath() 18
clipRegion() 18
clipRect(Region.Op.XOR) 18
clipRect(Region.Op.Difference) 18
clipRect(Region.Op.ReverseDifference) 18
clipRect() con rotazione/prospettiva 18
Verniciatura
setAntiAlias() (per il testo) 18
setAntiAlias() (per le righe) 16
setFilterBitmap() 17
setLinearText()
setMaskFilter()
setPathEffect() (per le righe) 28
setShadowlayer() (diverso dal testo) 28
setStrokeCap() (per le righe) 18
setStrokeCap() (per i punti) 19
setSubpixelText() 28
Modalità Xfer
PorterDuff.Mode.DARKEN (framebuffer) 28
PorterDuff.Mode.LIGHTEN (framebuffer) 28
PorterDuff.Mode.OVERLAY (framebuffer) 28
Ombreggiatore
ComposeShader all'interno di ComposeShader 28
Shar dello stesso tipo in ComposeShader 28
Matrice locale su ComposeShader 18

Scalabilità del canvas

La pipeline di rendering 2D con accelerazione hardware è stata creata prima per supportare i disegni non in scala, alcune operazioni di disegno riducono significativamente la qualità a valori di scala più elevati. Questi vengono implementate come texture disegnate in scala 1.0, trasformate dalla GPU. Avvio nell'API in corso... livello 28, tutte le operazioni di disegno possono scalare senza problemi.

La tabella seguente mostra quando l'implementazione è stata modificata per gestire correttamente su larga scala:
Operazione del disegno da scalare Primo livello API supportato
drawText() 18
drawPosText() 28
drawTextOnPath() 28
Forme semplici* 17
Forme complesse* 28
drawPath() 28
Livello ombra 28

Nota: "semplice" forme sono drawRect(), drawCircle(), drawOval(), drawRoundRect() e I comandi drawArc() (con useCenter=false) generati con un elemento Paint che non ha un PathEffect e non contiene join non predefiniti (tramite setStrokeJoin() / setStrokeMiter()). Altre istanze di questi comandi di disegno rientrano in "Complesso", nel nel grafico riportato sopra.

Se la tua applicazione presenta una di queste funzionalità o limitazioni mancanti, puoi: per disattivare l'accelerazione hardware solo per la parte interessata dell'applicazione chiamando setLayerType(View.LAYER_TYPE_SOFTWARE, null). In questo modo puoi sfruttare comunque l'accelerazione hardware in altri servizi. Per ulteriori informazioni su come attivare la funzionalità, consulta la sezione Controllare l'accelerazione hardware. e disattivare l'accelerazione hardware a diversi livelli nell'applicazione.

Visualizza livelli

In tutte le versioni di Android, le visualizzazioni hanno avuto la possibilità di eseguire il rendering in buffer fuori schermo, utilizzando la cache di disegno di una vista o Canvas.saveLayer(). I buffer fuori schermo, o livelli, hanno diversi utilizzi. Puoi utilizzarle per ottenere un rendimento migliore quando si animano viste complesse o nell'applicazione di effetti di composizione. Ad esempio, puoi implementare effetti di dissolvenza utilizzando Canvas.saveLayer() per eseguire il rendering temporaneo di una visualizzazione in un livello, per poi comporlo nuovamente sullo schermo con un fattore di opacità.

A partire da Android 3.0 (livello API 11), hai un maggiore controllo su come e quando utilizzare i livelli. con il metodo View.setLayerType(). Questa API richiede parametri: il tipo di livello che vuoi utilizzare e un Paint facoltativo che descrive come deve essere composto il livello. Puoi utilizzare il parametro Paint per applicare filtri di colore, modalità di fusione speciali oppure opacità a una livello di sicurezza. Una vista può utilizzare uno dei tre tipi di livelli:

  • LAYER_TYPE_NONE: la visualizzazione viene visualizzata normalmente e non è supportata da un buffer fuori schermo. Questo è il comportamento predefinito.
  • LAYER_TYPE_HARDWARE: la visualizzazione viene visualizzata nell'hardware in una texture hardware se l'applicazione è con accelerazione hardware. Se l'applicazione non è hardware accelerata, questo tipo di livello si comporta come LAYER_TYPE_SOFTWARE.
  • LAYER_TYPE_SOFTWARE: la visualizzazione viene visualizzata nel software in una bitmap.

Il tipo di livello utilizzato dipende dall'obiettivo:

  • Prestazioni: utilizza un tipo di livello hardware per eseguire il rendering di una vista in un hardware. texture. Dopo il rendering di una vista in un livello, non è necessario eseguire il codice di disegno finché la visualizzazione non chiama invalidate(). Alcune animazioni, ad esempio animazioni alfa, possono quindi essere applicate direttamente al livello, offrendo un'elevata efficienza per la GPU.
  • Effetti visivi: utilizza un tipo di livello hardware o software e un Paint per applicare trattamenti visivi speciali a una vista. Ad esempio, puoi disegna una vista in bianco e nero utilizzando un ColorMatrixColorFilter.
  • Compatibilità: utilizza un tipo di livello software per forzare il rendering di una vista. software. Se una vista con accelerazione hardware (ad esempio, se l'intero l'applicazione è hardware ottimizzata), presenta problemi di rendering, questo è un modo semplice sulle limitazioni del rendering hardware una pipeline o un blocco note personalizzato.

Visualizza livelli e animazioni

I livelli hardware possono offrire animazioni più veloci e fluide quando l'applicazione con accelerazione hardware. Non è sempre possibile eseguire un'animazione a 60 frame al secondo quando: che anima viste complesse che comportano molte operazioni di disegno. Questo può essere alleviato utilizzando i livelli hardware per eseguire il rendering della vista in una texture hardware. La texture hardware può essere poi utilizzato per animare la visualizzazione, eliminando così la necessità che si ridisegga costantemente durante l'animazione. La visualizzazione non viene ridisegnata, a meno che non modifichi il layout proprietà, che chiama invalidate() o se chiami invalidate() manualmente. Se esegui un'animazione in della tua applicazione e non ottenere i risultati desiderati, ti consigliamo di abilitare i livelli hardware le tue visualizzazioni animate.

Quando una vista è supportata da un livello hardware, alcune delle sue proprietà vengono gestite dal modo in cui viene composito sullo schermo. L'impostazione di queste proprietà sarà efficace perché non richiedere che la vista venga invalidata e ridisegnata. Il seguente elenco di proprietà influisce sul modo è composto il livello. Chiamare il setter per una di queste proprietà ha come risultato ottimale invalidazione e nessun ridisegno della vista target:

  • alpha: modifica l'opacità del livello
  • x, y, translationX e translationY: Modifica la posizione del livello
  • scaleX, scaleY: modifica le dimensioni del livello
  • rotation, rotationX, rotationY: modifica il orientamento del livello nello spazio 3D
  • pivotX, pivotY: cambia l'origine delle trasformazioni del livello

Queste proprietà sono i nomi utilizzati quando si anima una vista con un elemento ObjectAnimator. Se vuoi accedere a queste proprietà, chiama il setter o getter. Ad esempio, per modificare la proprietà alpha, chiama setAlpha(). Il seguente snippet di codice mostra il modo più efficiente per ruotare un punto di visualizzazione 3D intorno all'asse Y:

Kotlin

view.setLayerType(View.LAYER_TYPE_HARDWARE, null)
ObjectAnimator.ofFloat(view, "rotationY", 180f).start()

Java

view.setLayerType(View.LAYER_TYPE_HARDWARE, null);
ObjectAnimator.ofFloat(view, "rotationY", 180).start();

Poiché i livelli hardware consumano memoria video, ti consigliamo vivamente di abilitarli solo per la durata dell'animazione e poi disattivale al termine dell'animazione. Tu può farlo utilizzando i listener di animazioni:

Kotlin

view.setLayerType(View.LAYER_TYPE_HARDWARE, null)
ObjectAnimator.ofFloat(view, "rotationY", 180f).apply {
    addListener(object : AnimatorListenerAdapter() {
        override fun onAnimationEnd(animation: Animator) {
            view.setLayerType(View.LAYER_TYPE_NONE, null)
        }
    })
    start()
}

Java

view.setLayerType(View.LAYER_TYPE_HARDWARE, null);
ObjectAnimator animator = ObjectAnimator.ofFloat(view, "rotationY", 180);
animator.addListener(new AnimatorListenerAdapter() {
    @Override
    public void onAnimationEnd(Animator animation) {
        view.setLayerType(View.LAYER_TYPE_NONE, null);
    }
});
animator.start();

Per scoprire di più sull'animazione della proprietà, consulta la pagina Animazione della proprietà.

Suggerimenti utili

Il passaggio alla grafica 2D con accelerazione hardware può aumentare all'istante le prestazioni, ma deve comunque progettare l'applicazione in modo da utilizzare la GPU in modo efficace seguendo queste indicazioni: raccomandazioni:

Riduci il numero di visualizzazioni della tua applicazione
Più visualizzazioni deve disegnare il sistema, più lento sarà il processo. Questo vale per il software pipeline di rendering. Ridurre le visualizzazioni è uno dei modi più semplici per ottimizzare la tua UI.
Evitare l'overdraw
Non disegnare troppi livelli uno sopra l'altro. Rimuovi tutte le visualizzazioni completamente o da altre viste opache sulla parte superiore. Se devi disegnare più livelli mescolati sopra l'uno dall'altro, considera la possibilità di unirli in un unico livello. Una buona regola empirica con gli annunci l'hardware non deve disegnare più di 2,5 volte il numero di pixel sullo schermo per frame (pixel trasparenti in un conteggio bitmap).
Non creare oggetti di rendering nei metodi di disegno
Un errore comune è creare un nuovo Paint o un nuovo Path ogni volta che viene richiamato un metodo di rendering. Questa operazione forza l'eliminazione dei rifiuti in modo che venga eseguito più spesso e bypassa anche cache e ottimizzazioni nell'hardware una pipeline o un blocco note personalizzato.
Non modificare troppo spesso le forme
Forme, percorsi e cerchi complessi, ad esempio, vengono visualizzati utilizzando le maschere di texture. Ogni evento ogni volta che crei o modifichi un percorso, la pipeline hardware crea una nuova maschera, che può essere costoso.
Non modificare troppo spesso le bitmap
Ogni volta che modifichi i contenuti di una bitmap, questa viene caricata di nuovo come texture GPU la prossima volta che lo disegna.
Usare alpha con cautela
Quando crei una visualizzazione traslucida utilizzando setAlpha(), AlphaAnimation o ObjectAnimator viene eseguito in un buffer fuori schermo che raddoppia il tasso di riempimento richiesto. Durante l'applicazione di alpha nelle viste molto grandi, valuta la possibilità di impostare il tipo di livello della vista su LAYER_TYPE_HARDWARE.