Framerate mit adaptiver Aktualisierungsrate optimieren

, um die Geräteunterstützung zu prüfen.

Wenn in Android eine Animation gestartet wird, wird das Display oft auf die maximale Aktualisierungsrate hochgefahren, um eine flüssige Darstellung zu gewährleisten. Für kleine Animationen wie Fortschrittsbalken und Audio-Visualisierungen ist diese hohe Aktualisierungsrate nicht erforderlich und führt zu einem hohen Stromverbrauch.

Ab Android 15 können Geräte mit aktivierter Funktion für adaptive Aktualisierungsrate (Adaptive Refresh Rate, ARR) die Verweildauer bei hoher Aktualisierungsrate auf zwei Arten reduzieren:

  • Dank der neuen Optimierungen für die Verwaltung der Framerate auf der Plattform können Apps standardmäßig mit einer niedrigeren Framerate gerendert werden und nur bei Bedarf auf eine hohe Framerate umstellen.
  • Die Aktualisierungsrate des Displays wird dynamisch an die Renderingrate der Inhalte angepasst, ohne dass es zu Rucklern kommt.

Die meisten Apps sollten von ARR ohne Änderungen profitieren. Sie können das Standardverhalten der Framerate aber auch nach Bedarf überschreiben.

Auf dieser Seite wird Folgendes beschrieben:

  • So wird die Framerate der einzelnen Ansichten bestimmt.
  • Die allgemeine Richtlinie dafür, wie ARR die Framerate festlegt.
  • So können Sie das Standardverhalten der Framerate manuell überschreiben.

Der Abstimmungsmechanismus

Im View-System von Android kann jede View in der UI-Hierarchie ihre bevorzugte Framerate angeben. Diese Einstellungen werden erfasst und kombiniert, um eine endgültige Framerate für jeden Frame zu bestimmen. Dies wird durch einen Abstimmungsmechanismus erreicht, bei dem jede Ansicht basierend auf ihrem Attribut für die Bildrate abstimmt. Das Attribut kann eine Kategorie oder eine bestimmte Rate sein. Ansichten werden in der Regel bei der Darstellung oder Aktualisierung gerendert. Diese Stimmen werden kombiniert, um eine endgültige Framerate zu ermitteln, die dann als Hinweis für das Rendern an die untergeordnete Ebene gesendet wird.

Derzeit wird für die meisten Ansichten standardmäßig eine „normale“ Bildrate verwendet, die oft auf 60 Hz festgelegt ist. Für höhere Bildraten können Sie bestimmte APIs verwenden, um die Einstellungen anzupassen. Das System wählt in der Regel die höchste Bildrate aus. Weitere Informationen zur Verwendung dieser APIs finden Sie im Abschnitt Bildrate oder Kategorie festlegen. Die allgemeinen Richtlinien zu Bildraten werden im Abschnitt Allgemeine ARR-Richtlinie beschrieben.

Kategorien für Framerates

In der Klasse View gibt es verschiedene Kategorien für die Bildrate, die bei der Abstimmung verwendet werden können. Die einzelnen Kategorien werden so beschrieben:

  • REQUESTED_FRAME_RATE_CATEGORY_DEFAULT: Mit diesem Wert können Sie zum Standardverhalten zurückkehren. Er gibt an, dass für diese Ansicht keine Daten für die Bildrate vorhanden sind.
  • REQUESTED_FRAME_RATE_CATEGORY_NO_PREFERENCE: Die Ansicht hat keinen Einfluss auf die Framerate. Das bedeutet, dass das Framework die View bei der Bestimmung der Frame-Rate nicht berücksichtigt, auch wenn sie aktiv ist.
  • REQUESTED_FRAME_RATE_CATEGORY_NORMAL: Gibt eine mittlere Framerate an, die für Animationen geeignet ist, die keine höheren Frameraten erfordern oder von einer hohen Glätte nicht profitieren. Das sind normalerweise 60 Hz oder ein ähnlicher Wert.
  • REQUESTED_FRAME_RATE_CATEGORY_HIGH: Gibt eine Bildrate an, die für Animationen geeignet ist, die eine hohe Bildrate erfordern. Dies kann die Glätte erhöhen, aber auch den Stromverbrauch.

Eine Ansicht wird nur dann neu gerendert, wenn dies erforderlich ist. Die endgültige Framerate wird durch die höchste Anzahl an Stimmen bestimmt. Wenn beispielsweise alle Stimmen für „Normal“ abgegeben werden, wird „Normal“ ausgewählt. Wenn sowohl „Normal“- als auch „High“-Abstimmungen erfolgen, wird „High“ ausgewählt.

Framerate

Neben Frameratenkategorien kann in einer Ansicht auch eine bevorzugte Framerate angegeben werden, z. B. 30, 60 oder 120 Hz. Wenn mehrere Frameratenstimmen abgegeben werden, wird die endgültige Framerate anhand der folgenden Regeln bestimmt:

  • Vielfache voneinander: Wenn die ausgewählten Framerates Vielfache voneinander sind, wird der höchste Wert ausgewählt. Wenn es beispielsweise zwei Stimmen gibt – 30 Hz und 90 Hz –, wird 90 Hz als endgültige Bildrate ausgewählt.
  • Keine Vielfachen voneinander:
    • Wenn einer der Werte über 60 Hz liegt, wird er als „Hoch“ gewertet.
    • Wenn alle Stimmen 60 Hz oder weniger betragen, wird dies als „Normal“ gewertet.

Wenn sowohl Framerate-Werte als auch Framerate-Kategorien vorhanden sind, bestimmt in der Regel der höhere Wert die endgültige Renderrate. Bei einer Kombination aus einer Abstimmung mit 60 Hz und einer Abstimmung mit „Hoch“ oder einer Abstimmung mit 120 Hz und einer Abstimmung mit „Normal“ wird die Renderrate in der Regel auf 120 Hz festgelegt.

Zusätzlich zu den Stimmen aus einer App können auch andere Hinweise von verschiedenen Komponenten innerhalb desselben Frames an die untergeordnete Ebene gesendet werden. Viele dieser Probleme können durch System-UI-Komponenten wie den Benachrichtigungsbereich, die Statusleiste und die Navigationsleiste verursacht werden. Die endgültigen Werte für die Bildrate werden anhand der Stimmen mehrerer Komponenten ermittelt.

Framerate oder Kategorie festlegen

Unter bestimmten Umständen haben Sie möglicherweise eine bevorzugte Framerate für eine Ansicht. Sie können beispielsweise die bevorzugte Framerate für eine Ansicht auf „Hoch“ festlegen, um die Framerate zu erhöhen, wenn eine Animation nicht flüssig dargestellt wird. Wenn in einem Video eine langsame oder statische Animation zu sehen ist (die in der Regel mit 24 oder 30 Hz abgespielt wird), kann es sinnvoll sein, die Animation mit einer niedrigeren Rate als „Normal“ auszuführen, um den Stromverbrauch zu senken.

Mit den APIs setRequestedFrameRate() und getRequestedFrameRate() können Sie die bevorzugte Framerate oder Kategorie einer bestimmten Ansicht festlegen.

Kotlin

// Set the preferred frame rate category to a View

// set the frame rate category to NORMAL
view.requestedFrameRate = View.REQUESTED_FRAME_RATE_CATEGORY_NORMAL
// set the frame rate category to HIGH
view.requestedFrameRate = View.REQUESTED_FRAME_RATE_CATEGORY_HIGH
// reset the frame rate category
view.requestedFrameRate = View.REQUESTED_FRAME_RATE_CATEGORY_DEFAULT

// Set the preferred frame rate to a View

// set the frame rate to 30
view.requestedFrameRate = 30f
// set the frame rate to 60
view.requestedFrameRate = 60f
// set the frame rate to 120
view.requestedFrameRate = 120f

Java

// Set the preferred frame rate category to a View

// set the frame rate category to NORMAL
view.setRequestedFrameRate(View.REQUESTED_FRAME_RATE_CATEGORY_NORMAL);
// set the frame rate category to HIGH
view.setRequestedFrameRate(View.REQUESTED_FRAME_RATE_CATEGORY_HIGH);
// reset the frame rate category
view.setRequestedFrameRate(View.REQUESTED_FRAME_RATE_CATEGORY_DEFAULT);

// Set the preferred frame rate to a View

// set the frame rate to 30
view.setRequestedFrameRate(30);
// set the frame rate to 60
view.setRequestedFrameRate(60);
// set the frame rate to 120
view.setRequestedFrameRate(120);

Beispiele zur Verwendung finden Sie unter TextureView.

Allgemeine ARR-Richtlinie

Im vorherigen Abschnitt haben wir erläutert, dass die meisten Animationen standardmäßig mit 60 Hz angezeigt werden, da für jede View die bevorzugte Framerate auf „Normal“ festgelegt ist. Es gibt jedoch Ausnahmen, in denen die Framerate auf „Hoch“ erhöht wird, um flüssigere Animationen zu ermöglichen.

Die allgemeine ARR-Richtlinie lautet so:

  • Touch-Boost: Wenn ein Touch-Ereignis (MotionEvent.ACTION_DOWN) erkannt wird, wird die Aktualisierungsrate für einige Zeit nach dem Loslassen des Touch auf „Hoch“ erhöht, um die Reaktionsfähigkeit aufrechtzuerhalten.
  • Wischgesten: Wischgesten werden anders behandelt. Die Aktualisierungsrate nimmt allmählich ab, wenn die Wischgeschwindigkeit nachlässt. Weitere Informationen zu diesem Verhalten finden Sie im Abschnitt Verbesserung des Scrollens.
  • App-Start und Fensterübergänge: Die Aktualisierungsrate wird auch für einige Zeit beim Starten von Apps, bei der Fensterinitialisierung und bei Fensterübergängen erhöht, um eine flüssige Darstellung zu gewährleisten.
  • Animationen: Animationen, bei denen sich die Position oder Größe einer Ansicht ändert, erhalten automatisch eine höhere Aktualisierungsrate, um die Darstellung zu optimieren.
  • SurfaceView und TextureView: Frameraten, die explizit für TextureView und SurfaceView festgelegt wurden, werden berücksichtigt und entsprechend angewendet.

Touch-Boost aktivieren und deaktivieren

Sie können die Touch-Verstärkung auf Window-Ebene aktivieren und/oder deaktivieren. Standardmäßig erhöht sich die Rendering-Rate für einige Zeit, wenn ein Nutzer den Bildschirm berührt und den Finger wieder abhebt. Mit den APIs setFrameRateBoostOnTouchEnabled() und getFrameRateBoostOnTouchEnabled() können Sie verhindern, dass die Renderingrate steigt, wenn ein bestimmtes Window berührt wird.

Kotlin

// disable touch boost on a Window
window.isFrameRateBoostOnTouchEnabled = false 
// enable touch boost on a Window
window.isFrameRateBoostOnTouchEnabled = true
// check if touch boost is enabled on a Window
val isTouchBoostEnabled = window.isFrameRateBoostOnTouchEnabled

Java

// disable touch boost on a Window
window.setFrameRateBoostOnTouchEnabled(false)
// enable touch boost on a Window
window.setFrameRateBoostOnTouchEnabled(true)
// check if touch boost is enabled on a Window
window.getFrameRateBoostOnTouchEnabled()

Verbesserung beim Scrollen

Ein wichtiger Anwendungsfall für die dynamische Optimierung der Bildrate ist die Verbesserung des Scrollens (Fling). Viele Anwendungen sind darauf angewiesen, dass Nutzer nach oben wischen, um neue Inhalte zu sehen. Durch die ARR-Scrolloptimierung wird die Aktualisierungsrate dynamisch angepasst, wenn die Wischbewegung langsamer wird. Dadurch wird die Framerate allmählich reduziert. So wird das Rendering effizienter und das Scrollen bleibt flüssig.

Diese Verbesserung gilt speziell für scrollbare UI-Komponenten, einschließlich ScrollView, ListView und GridView, und ist möglicherweise nicht für alle benutzerdefinierten Implementierungen verfügbar.

Die ARR-Scrollfunktion ist für RecyclerView und NestedScrollView verfügbar. Wenn Sie diese Funktion in Ihrer App aktivieren möchten, führen Sie ein Upgrade auf die neuesten Versionen von AndroidX.recyclerview und AndroidX.core durch. Weitere Informationen finden Sie in der folgenden Tabelle.

Mediathek

Version

AndroidX.recyclerview

1.4.0

AndroidX.core

1.15.0

Geschwindigkeitsinformationen festlegen

Wenn Sie eine benutzerdefinierte scrollbare Komponente haben und die Scrollfunktion nutzen möchten, rufen Sie setFrameContentVelocity() in jedem Frame auf, während Sie sanft scrollen oder wischen. Hier ein Beispiel-Code-Snippet:

Kotlin

// set the velocity to a View (1000 pixels/Second)
view.frameContentVelocity = 1000f
// get the velocity of a View
val velocity = view.frameContentVelocity

Java

// set the velocity to a View
view.setFrameContentVelocity(velocity);

// get the velocity of a View
final float velocity = view.getFrameContentVelocity()

Weitere Beispiele finden Sie unter RecyclerView und ScrollView. Um die Geschwindigkeit richtig einzustellen, berechnen Sie die Inhaltsgeschwindigkeit (Pixel pro Sekunde) manuell, wenn die erforderlichen Informationen nicht aus Scroller oder OverScroller abgerufen werden können.

Wenn setFrameContentVelocity() und getFrameContentVelocity() für Ansichten aufgerufen werden, die keine scrollbaren Komponenten sind, haben sie keine Auswirkungen, da Bewegungen automatisch eine erhöhte Framerate basierend auf der aktuellen Richtlinie auslösen.

Die Geschwindigkeitsinformationen sind entscheidend für die Anpassung der Renderrate. Ein Beispiel ist die Wischbewegung. Zu Beginn kann die Geschwindigkeit eines Fling hoch sein, was eine höhere Rendering-Rate erfordert, um eine flüssige Wiedergabe zu gewährleisten. Im weiteren Verlauf der Geste nimmt die Geschwindigkeit ab, sodass die Rendering-Rate gesenkt werden kann.

ARR aktivieren und deaktivieren

ARR ist standardmäßig aktiviert, um die Energieeffizienz zu verbessern. Sie können diese Funktion zwar deaktivieren, es wird jedoch nicht empfohlen, da die App dann mehr Strom verbrauchen würde. Deaktivieren Sie diese Funktion nur, wenn Probleme auftreten, die die Nutzerfreundlichkeit erheblich beeinträchtigen.

Wenn Sie ARR aktivieren oder deaktivieren möchten, verwenden Sie die setFrameRatePowerSavingsBalanced() API für ein Window oder die isFrameRatePowerSavingsBalanced() API über Ihre styles.xml-Datei.

Das folgende Snippet zeigt, wie Sie ARR für eine Window aktivieren oder deaktivieren:

Kotlin

// disable ARR on a Window
window.isFrameRatePowerSavingsBalanced = false 
// enable ARR on a Window
window.isFrameRatePowerSavingsBalanced = true  
// check if ARR is enabled on a Window
val isAdaptiveRefreshRateEnabled = window.isFrameRatePowerSavingsBalanced

Java

// disable ARR on a Window
window.setFrameRatePowerSavingsBalanced(false)
// enable ARR on a Window
window.setFrameRatePowerSavingsBalanced(true)
// check if ARR is enabled on a Window
window.isFrameRatePowerSavingsBalanced()

Wenn Sie ARR über die Datei styles.xml deaktivieren möchten, fügen Sie Ihrem Stil in res/values/styles.xml das folgende Element hinzu:

<style name="frameRatePowerSavingsBalancedDisabled">
    <item name="android:windowIsFrameRatePowerSavingsBalanced">false</item>
</style>

ARR für Compose

Compose 1.9 unterstützt auch die adaptive Aktualisierungsrate. Im View-System verwenden Sie die Methode setRequestedFrameRate(), um eine bestimmte Framerate für eine View anzufordern. In Compose können Sie mit einem neuen Modifikator die Framerate für ein Composable angeben. Dieser Modifikator funktioniert ähnlich wie setRequestedFrameRate(). Er akzeptiert entweder einen positiven Wert für die Framerate (in Hz) oder eine vordefinierte Framerate-Kategorie, FrameRateCategory.

Die Signaturen für die APIs sind wie folgt:

Im Snippet unten wird der neue Frame-Raten-Modifikator (Modifier.requestedFrameRate(120f)) auf eine Text-Composable angewendet. Dieser Modifikator bewirkt, dass für die Text-Composable eine bevorzugte Framerate von 120 angefordert wird, wenn sie gerendert oder animiert wird (z. B. bei Änderungen der Deckkraft):

var targetAlpha by remember { mutableFloatStateOf(1f) }
val alpha by
    animateFloatAsState(
        targetValue = targetAlpha,
        animationSpec = tween(durationMillis = 1000)
    )

Button(
    onClick = { targetAlpha = if (targetAlpha == 1f) 0.2f else 1f },
    modifier =
        Modifier.background(LocalContentColor.current.copy(alpha = alpha))
) {
    Text(
        text = "Click",
        color = LocalContentColor.current.copy(alpha = alpha),
        modifier = Modifier.preferredFrameRate(120f)
     // You can also pass frame rate category such as FrameRateCategory.High  to increase the frame rate
    )
  }

Die bevorzugten Framerates aller Composables werden dann erfasst und zusammengefasst, um die endgültige Framerate für jeden Frame zu bestimmen. Weitere Informationen finden Sie unter SetFrameRateSample und SetFrameRateCategorySample.