Hardwarebeschleunigung

Ab Android 3.0 (API-Level 11) unterstützt die 2D-Rendering-Pipeline von Android Hardware Beschleunigung, d. h. alle Zeichenvorgänge, die auf einer Das Canvas von View verwendet die GPU. Aufgrund der erhöhten Ressourcen, die erforderlich sind, Hardwarebeschleunigung erfordert, dass Ihre App mehr RAM benötigt.

Die Hardwarebeschleunigung ist standardmäßig aktiviert, wenn dein Ziel-API-Level >= 14 ist, kann aber auch explizit aktiviert werden. Wenn Ihre Anwendung nur Standardansichten und Für Drawables sollte bei globaler Aktivierung keine nachteilige Zeichnung verursacht werden. Effekte. Da die Hardwarebeschleunigung jedoch nicht für alle 2D-Zeichnungen kann sich die Aktivierung auf einige Ihrer benutzerdefinierten Ansichten oder Zeichenaufrufe auswirken. Probleme äußern sich meist als unsichtbare Elemente, Ausnahmen oder falsch gerenderte Pixel. Bis Abhilfe können Sie in Android die Hardwarebeschleunigung an mehreren Niveau. Weitere Informationen finden Sie unter Hardwarebeschleunigung steuern.

Wenn Ihre Anwendung benutzerdefinierte Zeichnungen durchführt, testen Sie sie auf echten Hardwaregeräten. bei aktivierter Hardwarebeschleunigung, um Probleme zu finden. Im Abschnitt Unterstützung für Zeichenvorgänge werden bekannte Probleme mit Hardwarebeschleunigung und um diese zu umgehen.

Siehe auch OpenGL mit den Framework APIs und Renderscript

Hardwarebeschleunigung steuern

Sie können die Hardwarebeschleunigung auf den folgenden Ebenen steuern:

  • Wissen anwenden
  • Aktivität
  • Fenster
  • Ansehen

Anwendungsebene

Fügen Sie in Ihrer Android-Manifestdatei das folgende Attribut zum <ph type="x-smartling-placeholder"></ph> <application>-Tag, um die Hardwarebeschleunigung für die gesamte Anwendung:

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

Aktivitätslevel

Wenn sich Ihre Anwendung mit global aktivierter Hardwarebeschleunigung nicht ordnungsgemäß verhält, auch für einzelne Aktivitäten steuern. Um die Hardwarebeschleunigung zu aktivieren oder zu deaktivieren, Aktivitätsebene haben, können Sie das Attribut android:hardwareAccelerated für das <activity>-Element. Im folgenden Beispiel wird die Hardwarebeschleunigung für die gesamte Anwendung, deaktiviert sie jedoch für eine Aktivität:

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

Fensterebene

Wenn du eine noch genauere Steuerung benötigst, kannst du die Hardwarebeschleunigung für eine bestimmte Fenster mit dem folgenden Code:

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

Hinweis: Die Hardwarebeschleunigung kann derzeit nicht unter Fensterebene an.

Datenansichtsebene

Um die Hardwarebeschleunigung für eine einzelne Ansicht zur Laufzeit zu deaktivieren, verwenden Sie die folgenden Code:

Kotlin

myView.setLayerType(View.LAYER_TYPE_SOFTWARE, null)

Java

myView.setLayerType(View.LAYER_TYPE_SOFTWARE, null);

Hinweis: Sie können die Hardwarebeschleunigung derzeit nicht unter auf der Datenansichtsebene. Ansichtsebenen haben neben der Deaktivierung der Hardwarebeschleunigung noch weitere Funktionen. Weitere Informationen zu ihrer Verwendung finden Sie unter Ebenen ansehen.

Bestimmen, ob eine Ansicht hardwarebeschleunigt ist

Manchmal ist es hilfreich, wenn eine Anwendung weiß, ob es sich um Hardware handelt. insbesondere bei benutzerdefinierten Ansichten. Dies ist besonders nützlich, der Anwendung viele benutzerdefinierte Zeichnungen, und nicht alle Vorgänge werden vom neuen Rendering-Pipeline.

Es gibt zwei Möglichkeiten, um zu prüfen, ob eine Anwendung hardwarebeschleunigt ist:

Wenn Sie dies in Ihrem Zeichencode tun müssen, verwenden Sie Stattdessen Canvas.isHardwareAccelerated() von View.isHardwareAccelerated(). Wenn ein Aufruf an einem hardwarebeschleunigten Fenster montiert ist, kann es dennoch mit anderen beschleunigten Canvas. Dies geschieht z. B. beim Zeichnen einer Ansicht in eine Bitmap zur Speicherung im Cache. zu verstehen.

Android-Zeichnungsmodelle

Wenn die Hardwarebeschleunigung aktiviert ist, nutzt das Android-Framework ein neues Zeichenmodell, nutzt Anzeigelisten, um Ihre App auf dem Bildschirm zu rendern. Um das Verständnis und wie sich diese auf Ihre Anwendung auswirken können, sollten Sie wissen, auch ohne Hardwarebeschleunigung. In den folgenden Abschnitten wird beschrieben, softwarebasierte und hardwarebeschleunigte Zeichenmodelle.

Softwarebasiertes Zeichenmodell

Im Software-Zeichenmodell werden Ansichten in den folgenden zwei Schritten gezeichnet:

  1. Hierarchie ungültig machen
  2. Hierarchie zeichnen

Wenn eine Anwendung einen Teil ihrer UI aktualisieren muss, wird invalidate() (oder eine ihrer Varianten) für jede Ansicht aufgerufen, die sich geändert hat. Inhalte. Die Entwertungsmeldungen werden zu Berechnungszwecken in der Ansichtshierarchie nach oben weitergegeben. die Bereiche des Bildschirms, die neu gezeichnet werden müssen (der schmutzige Bereich). Das Android-System zeichnet jede Ansicht in der Hierarchie, die sich mit dem schmutzigen Bereich überschneidet. Leider gibt es Dieses Zeichnungsmodell hat zwei Nachteile:

  • Erstens muss bei diesem Modell bei jedem Zeichendurchlauf viel Code ausgeführt werden. Wenn beispielsweise Ihre Anwendung invalidate() für eine Schaltfläche aufruft und dass über einer anderen Ansicht befindet, zeichnet das Android-System die Ansicht neu, obwohl dies geändert.
  • Das zweite Problem besteht darin, dass das Zeichnungsmodell Programmfehler in Ihrer Anwendung verstecken kann. Da die Das Android-System erstellt Ansichten neu, wenn sie sich mit der schmutzigen Region überschneiden, einer Ansicht, deren Inhalte du geändert möglicherweise neu gezeichnet, obwohl invalidate() nicht gearbeitet hat. In diesem Fall verlassen Sie sich darauf, dass eine andere Ansicht für ungültig erklärt wird, um den für ein korrektes Verhalten. Dieses Verhalten kann sich jedes Mal ändern, wenn Sie Ihre Anwendung ändern. Aus sollten Sie immer invalidate() für Ihre benutzerdefinierte wenn Sie Daten oder Status ändern, die sich auf den Zeichencode der Ansicht auswirken.

Hinweis: Android-Ansichten rufen automatisch invalidate() auf, wenn sich ihre Eigenschaften ändern, z. B. der Hintergrund. Farbe oder den Text in TextView.

Hardwarebeschleunigtes Zeichnenmodell

Das Android-System verwendet weiterhin invalidate() und draw(), um Bildschirmupdates anzufordern und Ansichten zu rendern, es verarbeitet aber tatsächliche Zeichnung anders. Anstatt die Zeichenbefehle sofort auszuführen, werden sie in Anzeigelisten aufgezeichnet, die die Ausgabe der Code zu zeichnen. Eine weitere Optimierung besteht darin, dass das Android-System Displaylisten für Ansichten, die von einem invalidate() als als als schmutzig gekennzeichnet sind aufrufen. Ansichten, die nicht ungültig gemacht wurden, können einfach durch erneutes Ausstellen des zuvor der Display-Aufzeichnungen. Das neue Zeichnungsmodell umfasst drei Phasen:

  1. Hierarchie ungültig machen
  2. Displaylisten aufzeichnen und aktualisieren
  3. Anzeigelisten zeichnen

Bei diesem Modell können Sie sich nicht darauf verlassen, dass die Methode draw() von einer Ansicht ausgeführt wird, die den schmutzigen Bereich überschneidet. Um sicherzustellen, dass das Android-System angezeigt wird, müssen Sie invalidate() aufrufen. Wird entfernt führt dies dazu, dass eine Ansicht auch nach einer Änderung gleich aussieht.

Die Verwendung von Displaylisten verbessert auch die Animationsleistung, da wie Alpha- oder Rotationstechnik, muss die Ansicht mit der Ausrichtung nicht ungültig werden. automatisch). Diese Optimierung gilt auch für Aufrufe mit Displaylisten, also für alle Aufrufe, die Anwendung hardwarebeschleunigt ist.) Angenommen, es gibt eine LinearLayout, die eine ListView über Button enthält. Die Anzeigeliste für LinearLayout sieht wie folgt aus: dies:

  • DrawDisplayList(ListView)
  • DrawDisplayList(Schaltfläche)

Angenommen, Sie möchten die Deckkraft von ListView ändern. Nachher Durch Aufrufen von setAlpha(0.5f) für ListView wird die Anzeigeliste nun enthält Folgendes:

  • SaveLayerAlpha(0.5)
  • DrawDisplayList(ListView)
  • Wiederherstellen
  • DrawDisplayList(Schaltfläche)

Der komplexe Zeichencode von ListView wurde nicht ausgeführt. Stattdessen Das System hat lediglich die Anzeigeliste der wesentlich einfacheren LinearLayout aktualisiert. In bei einer Anwendung ohne aktivierte Hardwarebeschleunigung, den Zeichencode der Liste und der Parent werden noch einmal ausgeführt.

Unterstützung für Zeichenvorgänge

Bei einer hardwarebeschleunigten 2D-Rendering-Pipeline unterstützt die 2D-Rendering-Pipeline die am häufigsten verwendeten Canvas-Zeichnungsvorgänge und viele weniger häufig verwendete Vorgänge. Alle Zeichenoperationen, die zum Rendern von Android-Anwendungen verwendet werden, sind Standard-Widgets Layouts und gängige erweiterte visuelle Effekte wie Reflexionen und gekachelte Texturen unterstützt.

In der folgenden Tabelle wird die Unterstützungsstufe für verschiedene Vorgänge auf allen API-Ebenen beschrieben:

Erstes unterstütztes API-Level
Canvas
drawBitmapMesh() (Farbarray) 18
drawPicture() 23
drawPosText() 16
drawTextOnPath() 16
drawVertices() 29
setDrawFilter() 16
ClipPath() 18
ClipRegion() 18
ClipRect(Region.Op.XOR) 18
ClipRect(Region.Op.Differenz) 18
ClipRect(Region.Op.ReverseDifference) 18
ClipRect() mit Drehung/Perspektive 18
Farbe
setAntiAlias() (für Text) 18
setAntiAlias() (für Zeilen) 16
setFilterBitmap() 17
setLinearText()
setMaskFilter()
setPathEffect() (für Linien) 28
setShadowLayer() (außer Text) 28
setStrokeCap() (für Linien) 18
setStrokeCap() (für Punkte) 19
setSubpixelText() 28
Xfer-Modus
PorterDuff.Mode.DARKEN (Framebuffer) 28
PorterDuff.Mode.LIGHTEN (Framebuffer) 28
PorterDuff.Mode.OVERLAY (Framebuffer) 28
Shader
ComposeShader in ComposeShader 28
Gleiche Shader in ComposeShader 28
Lokale Matrix in ComposeShader 18

Canvas-Skalierung

Die hardwarebeschleunigte 2D-Rendering-Pipeline wurde zuerst entwickelt, um das Zeichnen ohne Skalierung zu unterstützen, wobei einige Zeichenvorgänge bei höheren Skalenwerten die Qualität erheblich verschlechtern. Diese Operationen werden als Texturen implementiert, die im Maßstab 1.0 gezeichnet und von der GPU transformiert werden. In API starten Ebene 28 können alle Zeichenvorgänge problemlos skaliert werden.

In der folgenden Tabelle sehen Sie, wann die Implementierung geändert wurde, damit große Datenmengen korrekt verarbeitet werden können:
Zu skalierender Zeichnungsvorgang Erstes unterstütztes API-Level
drawText() 18
drawPosText() 28
drawTextOnPath() 28
Einfache Formen* 17
Komplexe Formen* 28
DrawPath(): 28
Schattenebene 28

Hinweis: „Einfach“ Formen sind drawRect(), drawCircle(), drawOval(), drawRoundRect() und drawArc()-Befehle (mit useCenter=false) für Paint ohne PathEffect und enthält keine nicht standardmäßigen Joins (über setStrokeJoin() / setStrokeMiter(). Andere Instanzen dieser Zeichenbefehle fallen unter "Komplex", in im obigen Diagramm.

Wenn Ihre App von einer dieser fehlenden Funktionen oder Einschränkungen betroffen ist, können Sie deaktivieren Sie die Hardwarebeschleunigung nur für den betroffenen Teil Ihrer Anwendung, indem Sie den Aufruf setLayerType(View.LAYER_TYPE_SOFTWARE, null) Auf diese Weise können Sie und überall sonst die Hardwarebeschleunigung nutzen. Weitere Informationen zum Aktivieren der Funktion findest du unter Hardwarebeschleunigung steuern. und deaktivieren Sie die Hardwarebeschleunigung auf verschiedenen Stufen in Ihrer Anwendung.

Ebenen ansehen

In allen Android-Versionen konnten Aufrufe in Zwischenspeicher außerhalb des Bildschirms entweder mithilfe des Zeichencaches einer Ansicht oder mithilfe von Canvas.saveLayer(). Für Zwischenspeicher außerhalb des Bildschirms oder Ebenen gibt es mehrere Verwendungszwecke. Sie können sie nutzen, bessere Leistung bei der Animation komplexer Ansichten oder beim Anwenden von Kompositionseffekten Beispiel: Sie können Ausblendungseffekte mit Canvas.saveLayer() implementieren, um eine Ansicht vorübergehend zu rendern in eine Ebene umwandeln und anschließend mit einem Deckkraftfaktor wieder auf dem Bildschirm darstellen.

Ab Android 3.0 (API-Level 11) haben Sie mehr Kontrolle darüber, wie und wann Sie Ebenen verwenden. mit der Methode View.setLayerType(). Diese API verwendet zwei Parameter: der Ebenentyp, den Sie verwenden möchten, und ein optionales Paint -Objekt, das beschreibt, wie die Ebene zusammengesetzt werden soll. Mit dem Parameter Paint können Sie Farbfilter, spezielle Mischmodi oder die Deckkraft auf ein Element anwenden. Ebene. Für Ansichten kann einer von drei Ebenentypen verwendet werden:

  • LAYER_TYPE_NONE: Die Ansicht wird normal gerendert und nicht gesichert. durch einen Zwischenspeicher außerhalb des Bildschirms gesprochen. Dies ist die Standardeinstellung.
  • LAYER_TYPE_HARDWARE: Die Ansicht wird Hardware in einen Hardware-Textur, wenn die Anwendung hardwarebeschleunigt ist. Wenn die Anwendung keine Hardware ist beschleunigt wird, verhält sich dieser Ebenentyp genauso wie LAYER_TYPE_SOFTWARE.
  • LAYER_TYPE_SOFTWARE: Die Ansicht wird in Software in ein Bitmap.

Welche Art von Ebene Sie verwenden, hängt von Ihrem Ziel ab:

  • Leistung: Verwenden Sie einen Hardwareebenentyp, um eine Ansicht in eine Hardware zu rendern. Textur. Sobald eine Ansicht in einer Ebene gerendert wurde, muss ihr Zeichencode nicht mehr ausgeführt werden bis die Ansicht invalidate() aufruft. Einige Animationen, wie z. B. Alpha-Animationen können anschließend direkt auf die Ebene angewendet werden, die die GPU erledigen soll.
  • Visuelle Effekte: Verwenden Sie einen Hardware- oder Softwareebenentyp und einen Paint, um eine Ansicht mit besonderen visuellen Effekten zu versehen. Zum Beispiel können Sie Zeichnen Sie eine schwarz-weiße Ansicht mit ColorMatrixColorFilter.
  • Kompatibilität: Verwenden Sie einen Softwareebenentyp, um das Rendern einer Ansicht zu erzwingen. Software. Wenn eine hardwarebeschleunigte Ansicht (z. B. wenn Ihr gesamter Hardwarebeschleunigung), Rendering-Probleme haben, ist dies eine einfache Möglichkeit, zu Einschränkungen des Hardware-Renderings zu erstellen.

Ebenen und Animationen ansehen

Hardwareebenen können schnellere und flüssigere Animationen liefern, wenn Ihre Anwendung ist hardwarebeschleunigt. Eine Animation mit 60 Bildern pro Sekunde ist nicht immer möglich, Animieren komplexer Ansichten, die viele Zeichenvorgänge ausführen. Dies lässt sich beheben, indem mit Hardwareebenen, um die Ansicht als Hardware-Textur zu rendern. Die Hardware-Textur kann dann zum Animieren der Ansicht verwendet werden, sodass die Ansicht sich nicht ständig neu zeichnen muss. wenn es animiert ist. Die Ansicht wird erst dann neu gezeichnet, wenn Sie die Eigenschaften, die invalidate() aufrufen, oder wenn Sie invalidate() manuell aufrufen. Wenn Sie eine Animation in und erzielen nicht die gewünschten flüssigen Ergebnisse, sollten Sie erwägen, Hardwareschichten auf Ihre animierten Ansichten.

Wenn eine Ansicht von einer Hardwareschicht gestützt wird, werden einige ihrer Eigenschaften über die Art und Weise verarbeitet, ist auf dem Bildschirm aufgebaut. Das Festlegen dieser Eigenschaften ist effizient, da sie die Ansicht ungültig gemacht und neu gezeichnet werden. Die folgende Liste von Properties beeinflusst, aus der Schicht besteht. Das Aufrufen des Setters für eine dieser Eigenschaften führt zu optimalen Entwertung und kein erneutes Zeichnen der Zielansicht:

  • alpha: ändert die Deckkraft der Ebene.
  • x, y, translationX, translationY: Ändert die Position der Ebene
  • scaleX, scaleY: Ändert die Größe der Ebene.
  • rotation, rotationX, rotationY: Ändert die Ausrichtung der Ebene im 3D-Raum
  • pivotX, pivotY: Ändert den Ursprung der Transformationen der Ebene.

Diese Eigenschaften sind die Namen, die beim Animieren einer Ansicht mit einem ObjectAnimator verwendet werden. Wenn Sie auf diese Eigenschaften zugreifen möchten, rufen Sie die entsprechende Setter oder Getter. Wenn Sie beispielsweise das Attribut „Alpha“ ändern möchten, rufen Sie setAlpha() auf. Das folgende Code-Snippet zeigt die effizienteste Methode, , um ein 3D-Ansicht um die Y-Achse zu drehen:

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();

Da Hardwareebenen den Videospeicher verbrauchen, wird dringend empfohlen, sie zu aktivieren. nur für die Dauer der Animation und deaktivieren sie nach Abschluss der Animation. Ich erreichen Sie dies mithilfe von Animations-Listenern:

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();

Weitere Informationen zur Property-Animation finden Sie unter Property-Animation.

Tipps und Tricks

Ein Wechsel zu hardwarebeschleunigter 2D-Grafik kann die Leistung sofort steigern, aber ihr Ihre Anwendung dennoch für eine effektive Nutzung der GPU entwickeln. Empfehlungen:

Anzahl der Aufrufe in Ihrer Anwendung reduzieren
Je mehr Ansichten das System erstellen muss, desto langsamer wird es. Dies gilt für die Software, Rendering-Pipeline aus. Das Reduzieren der Aufrufe ist eine der einfachsten Möglichkeiten, deine Benutzeroberfläche zu optimieren.
Überzeichnung vermeiden
Zeichnen Sie nicht zu viele Ebenen übereinander. Entfernen Sie alle Datenansichten, die vollständig oder durch andere dunkle Ansichten verdeckt wird. Wenn Sie mehrere Ebenen übereinander sollten Sie sie in einer Ebene zusammenführen. Eine gute Faustregel im Hinblick auf die aktuelle darf nicht mehr als das 2,5-fache der Pixelanzahl auf dem Bildschirm pro Frame gezeichnet werden. (transparente Pixel in einer Bitmap-Zählung!).
Keine Renderingobjekte in Zeichenmethoden erstellen
Ein häufiger Fehler besteht darin, bei jedem Aufruf einer Renderingmethode ein neues Paint- oder Path-Objekt zu erstellen. Dadurch wird der Speicher Collector kann häufiger ausgeführt werden. Außerdem werden Caches und Optimierungen in der Hardware umgangen. zu erstellen.
Formen nicht zu oft ändern
Komplexe Formen, Pfade und Kreise werden beispielsweise mithilfe von Texturmasken gerendert. Jeden erstellt oder geändert, erstellt die Hardwarepipeline eine neue Maske, die teuer sein.
Bitmaps nicht zu oft ändern
Jedes Mal, wenn Sie den Inhalt einer Bitmap ändern, wird sie wieder als GPU-Textur hochgeladen. wenn Sie es das nächste Mal zeichnen.
Alphaversion mit Vorsicht verwenden
Wenn Sie mit setAlpha() eine durchsichtige Ansicht erstellen, AlphaAnimation oder ObjectAnimator in einem Zwischenspeicher außerhalb des Bildschirms gerendert, wodurch sich die erforderliche Ausführungsrate verdoppelt. Bei Anwendung von Alpha-Funktionen sehr großen Ansichten verwenden, können Sie den Ebenentyp der Ansicht auf LAYER_TYPE_HARDWARE