Leistungs- und Ansichtshierarchien

Die Art und Weise, wie Sie die Hierarchie Ihrer View-Objekte verwalten, kann die Leistung Ihrer Anwendung erheblich beeinträchtigen. Auf dieser Seite wird beschrieben, wie Sie beurteilen können, ob Ihre Ansichtshierarchie die Anwendung verlangsamt. Außerdem werden einige Strategien zum Beheben von Problemen vorgestellt.

Auf dieser Seite geht es vorrangig um die Verbesserung von View-basierten Layouts. Informationen zur Verbesserung der Jetpack Compose-Leistung finden Sie unter Jetpack Compose-Leistung.

Layout und Leistungsmessung

Die Rendering-Pipeline umfasst eine Layout-and-measure-Phase, in der das System die relevanten Elemente in Ihrer Ansichtshierarchie richtig positioniert. Der Teil measure dieser Phase bestimmt die Größe und Grenzen von View-Objekten. Der Teil layout bestimmt, wo auf dem Bildschirm die View-Objekte platziert werden.

Für beide Pipelinephasen fallen geringe Kosten pro Ansicht oder Layout an. In den meisten Fällen sind diese Kosten minimal und wirken sich nicht merklich auf die Leistung aus. Sie kann jedoch größer sein, wenn eine App View-Objekte hinzufügt oder entfernt, z. B. wenn ein RecyclerView-Objekt sie wiederverwendet oder wiederverwendet. Die Kosten können auch höher sein, wenn für ein View-Objekt eine Größenanpassung erforderlich ist, um die Einschränkungen zu erfüllen. Wenn Ihre Anwendung beispielsweise SetText() für ein View-Objekt aufruft, das Text umbricht, muss möglicherweise die Größe des View-Elements angepasst werden.

Wenn solche Fälle zu lange dauern, verhindern sie, dass ein Frame innerhalb der zulässigen 16 ms gerendert wird. Dies kann dazu führen, dass Frames ausfallen und Animationen verzögert angezeigt werden.

Da Sie diese Vorgänge nicht in einen Worker-Thread verschieben können, weil Ihre Anwendung sie im Hauptthread verarbeiten muss, sollten Sie sie so optimieren, dass sie so wenig Zeit wie möglich in Anspruch nehmen.

Komplexe Layouts verwalten

Mit Android-Layouts können Sie UI-Objekte in der Ansichtshierarchie verschachteln. Diese Verschachtelung kann auch Layoutkosten verursachen. Wenn Ihre App ein Objekt für das Layout verarbeitet, führt sie denselben Prozess auch für alle untergeordneten Elemente des Layouts durch.

Bei einem komplizierten Layout fallen manchmal Kosten nur dann an, wenn das System das Layout zum ersten Mal berechnet. Wenn Ihre Anwendung beispielsweise ein komplexes Listenelement in einem RecyclerView-Objekt wiederverwendet, muss das System alle Objekte neu anordnen. In einem anderen Beispiel können sich triviale Änderungen in der Kette nach oben in Richtung des übergeordneten Elements ausbreiten, bis sie ein Objekt erreichen, das sich nicht auf die Größe des übergeordneten Elements auswirkt.

Ein häufiger Grund dafür, dass das Layout lange dauert, ist, dass Hierarchien von View-Objekten ineinander verschachtelt sind. Durch jedes verschachtelte Layoutobjekt fallen Kosten für die Layoutphase an. Je flacher Ihre Hierarchie ist, desto weniger Zeit dauert die Ausführung der Layoutphase.

Wir empfehlen, ein ConstraintLayout statt mit RelativeLayout oder LinearLayout mit dem Layout-Editor zu erstellen, da dies im Allgemeinen effizienter ist und die Verschachtelung von Layouts reduziert. Für einfache Layouts, die mit FrameLayout erreicht werden können, empfehlen wir jedoch die Verwendung von FrameLayout.

Wenn Sie die Klasse RelativeLayout verwenden, können Sie möglicherweise denselben Effekt bei geringeren Kosten erzielen, wenn Sie stattdessen verschachtelte, ungewichtete LinearLayout-Ansichten verwenden. Wenn Sie jedoch verschachtelte, gewichtete LinearLayout-Ansichten verwenden, sind die Layoutkosten viel höher, da dafür mehrere Layoutdurchläufe erforderlich sind, wie im nächsten Abschnitt erläutert.

Außerdem empfehlen wir die Verwendung von RecyclerView anstelle von ListView. Dadurch können die Layouts einzelner Listenelemente wiederverwendet werden. Das ist nicht nur effizienter, sondern kann auch die Scrollleistung verbessern.

Doppelte Besteuerung

In der Regel führt das Framework das Layout oder die Messungsphase in einem einzigen Durchlauf aus. Bei einigen komplizierten Layoutfällen muss das Framework jedoch möglicherweise mehrere Teile der Hierarchie iterieren, für die mehrere Durchgänge erforderlich sind, bevor die Elemente schließlich positioniert werden. Die Vorgabe mehrerer Layout- und Messdurchläufe wird als doppelte Besteuerung bezeichnet.

Wenn Sie beispielsweise den RelativeLayout-Container verwenden, mit dem Sie View-Objekte in Bezug auf die Positionen anderer View-Objekte positionieren können, führt das Framework die folgende Sequenz aus:

  1. Führt einen Layout- und Messwertdurchlauf aus, bei dem das Framework die Position und Größe jedes untergeordneten Objekts basierend auf der Anfrage jedes untergeordneten Objekts berechnet.
  2. Nutzt diese Daten unter Berücksichtigung der Objektgewichte, um die richtige Position korrelierter Ansichten zu ermitteln.
  3. Führt einen zweiten Layoutübergang aus, um die Positionen der Objekte abzuschließen.
  4. Die nächste Phase des Renderingprozesses wird erreicht.

Je mehr Ebenen die Ansichtshierarchie aufweist, desto höher ist die Gefahr von Leistungseinbußen.

Wie bereits erwähnt, ist ConstraintLayout im Allgemeinen effizienter als andere Layouts außer FrameLayout. Es ist weniger anfällig für mehrere Layoutdurchläufe und in vielen Fällen ist es nicht erforderlich, Layouts zu verschachteln.

Andere Container als RelativeLayout können ebenfalls die Doppelbesteuerung erhöhen. Beispiel:

  • Eine LinearLayout-Ansicht kann bei horizontaler Darstellung zu einem doppelten Layout- und Messungsdurchlauf führen. Wenn du measureWithLargestChild hinzufügst, kann das Framework auch bei einer vertikalen Ausrichtung einen doppelten Durchlauf und einen zweiten Durchgang durchlaufen.
  • Der GridLayout ermöglicht zwar auch eine relative Positionierung, vermeidet jedoch doppelte Besteuerung, indem die Positionsbeziehungen zwischen untergeordneten Ansichten vorverarbeitet werden. Wenn im Layout jedoch Gewichtungen oder Füllungen mit der Klasse Gravity verwendet werden, geht der Vorteil der Vorverarbeitung verloren und das Framework muss möglicherweise mehrere Durchgänge ausführen, wenn der Container ein RelativeLayout ist.

Mehrere Durchgänge für Layout und Messung stellen nicht unbedingt eine Leistungsbeeinträchtigung dar. Sie können jedoch zu einer Belastung werden, wenn sie sich am falschen Ort befinden. Seien Sie vorsichtig, wenn eine der folgenden Bedingungen auf Ihren Container zutrifft:

  • Es ist ein Stammelement in Ihrer Ansichtshierarchie.
  • Unter ihr befindet sich eine tiefgehende Ansichtshierarchie.
  • Es wird in vielen Fällen auf dem Bildschirm dargestellt, ähnlich wie Kinder in einem ListView-Objekt.

Probleme in der Ansichtshierarchie diagnostizieren

Die Layoutleistung ist ein komplexes Problem mit vielen Facetten. Mit den folgenden Tools können Sie feststellen, wo Leistungsengpässe auftreten. Einige Tools liefern weniger konkrete Informationen, können aber hilfreiche Tipps geben.

Perfetto

Perfetto ist ein Tool, das Daten zur Leistung bereitstellt. Sie können Android-Traces in der Perfetto-UI öffnen.

GPU-Rendering für Profil

Das On-Device-Tool für das Profil-GPU-Rendering, das auf Geräten mit Android 6.0 (API-Level 23) und höher verfügbar ist, kann Ihnen konkrete Informationen zu Leistungsengpässen liefern. Mit diesem Tool kannst du sehen, wie lange die Phase "Layout and Measure" für jeden Rendering-Frame dauert. Anhand dieser Daten lassen sich Probleme mit der Laufzeitleistung diagnostizieren und so ermitteln, welche Layout- und Messprobleme Sie beheben müssen.

Bei der grafischen Darstellung der erfassten Daten verwendet das Profil-GPU-Rendering die Farbe Blau, um die Layoutzeit darzustellen. Weitere Informationen zur Verwendung dieses Tools finden Sie unter Profil-GPU-Renderinggeschwindigkeit.

Fussel

Das Lint-Tool von Android Studio kann Ihnen ein Gefühl für die Ineffizienzen in der Ansichtshierarchie verschaffen. Wählen Sie Analysieren > Code prüfen aus, um dieses Tool zu verwenden, wie in Abbildung 1 dargestellt.

Abbildung 1: Wählen Sie in Android Studio Code prüfen aus.

Informationen zu verschiedenen Layoutelementen finden Sie unter Android > Lint > Leistung. Klicken Sie auf die einzelnen Elemente, um sie zu maximieren und weitere Informationen im Bereich auf der rechten Seite des Bildschirms anzuzeigen. Abbildung 2 zeigt ein Beispiel für erweiterte Informationen.

Abbildung 2: Aufrufen von Informationen zu bestimmten Problemen, die vom Lint-Tool erkannt werden.

Wenn Sie auf ein Element klicken, werden im Bereich rechts die damit verbundenen Probleme angezeigt.

Weitere Informationen zu bestimmten Themen und Problemen in diesem Bereich finden Sie in der Lint-Dokumentation.

Layout Inspector

Das Tool Layout Inspector von Android Studio bietet eine visuelle Darstellung der Ansichtshierarchie Ihrer App. Sie bietet eine gute Möglichkeit, sich in der Hierarchie Ihrer App zurechtzufinden. Sie bietet eine klare visuelle Darstellung der übergeordneten Kette einer bestimmten Ansicht und ermöglicht es Ihnen, die von Ihrer App erstellten Layouts zu überprüfen.

Die vom Layout Inspector präsentierten Ansichten können auch dabei helfen, Leistungsprobleme aufgrund von doppelter Besteuerung zu erkennen. Sie können damit auch tiefe Ketten verschachtelter Layouts oder Layoutbereiche mit vielen verschachtelten untergeordneten Elementen identifizieren, was zu Leistungskosten führen kann. In diesen Fällen können die Layout- und Messphasen kostspielig sein und zu Leistungsproblemen führen.

Weitere Informationen finden Sie unter Layoutfehler mit Layout Inspector und Layout Validation beheben.

Probleme mit der Ansichtshierarchie beheben

Das grundlegende Konzept der Lösung von Leistungsproblemen, die aus Ansichtshierarchien entstehen, kann in der Praxis schwierig sein. Wenn Sie verhindern möchten, dass durch Ansichtshierarchien Leistungseinbußen verhängt werden, wird die Ansichtshierarchie vereinfacht und Doppelbesteuerungen reduziert. In diesem Abschnitt werden Strategien besprochen, um diese Ziele zu erreichen.

Redundante verschachtelte Layouts entfernen

ConstraintLayout ist eine Jetpack-Bibliothek mit einer Vielzahl verschiedener Mechanismen zur Positionierung von Ansichten im Layout. Dadurch ist kein Verschachteln von ConstaintLayout erforderlich und die Ansichtshierarchie wird vereinfacht. Es ist normalerweise einfacher, Hierarchien mit ConstraintLayout im Vergleich zu anderen Layouttypen abzuflachen.

Entwickler verwenden oft mehr verschachtelte Layouts als nötig. Beispielsweise kann ein RelativeLayout-Container ein einzelnes untergeordnetes Element enthalten, das auch ein RelativeLayout-Container ist. Diese Verschachtelung ist redundant und verursacht unnötige Kosten für die Ansichtshierarchie. Lint kann dieses Problem für Sie melden und so die Fehlerbehebungszeit verkürzen.

Zusammenführung übernehmen oder einschließen

Eine häufige Ursache für redundante verschachtelte Layouts ist das Tag <include>. Ein wiederverwendbares Layout könnte beispielsweise so definiert werden:

<LinearLayout>
    <!-- some stuff here -->
</LinearLayout>

Anschließend können Sie ein <include>-Tag hinzufügen, um dem übergeordneten Container das folgende Element hinzuzufügen:

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

Beim obigen Beispiel wird das erste Layout unnötigerweise im zweiten Layout verschachtelt.

Mit dem Tag <merge> lässt sich dieses Problem vermeiden. Informationen zu diesem Tag finden Sie unter <merge>-Tag verwenden.

Ein günstigeres Layout verwenden

Möglicherweise können Sie Ihr vorhandenes Layoutschema nicht so anpassen, dass es keine redundanten Layouts enthält. In bestimmten Fällen kann die einzige Lösung darin bestehen, die Hierarchie zu vereinfachen, indem Sie zu einem völlig anderen Layouttyp wechseln.

Sie könnten beispielsweise feststellen, dass TableLayout die gleiche Funktionalität wie ein komplexeres Layout mit vielen Positionsabhängigkeiten bietet. Die Jetpack-Bibliothek ConstraintLayout bietet ähnliche Funktionen wie RelativeLayout sowie weitere Funktionen zum Erstellen einfacherer, effizienterer Layouts.