Mit der Framerate API können Apps die Android-Plattform über den beabsichtigten Frame informieren. und ist nur für Apps verfügbar, die auf Android 11 (API-Level 30) oder höher ausgerichtet sind. Bisher haben die meisten Geräte nur eine einzige Displayaktualisierungsrate unterstützt, in der Regel 60 Hz. Das ändert sich jedoch. Viele Geräte unterstützen jetzt zusätzliche Bildwiederholraten wie 90 Hz oder 120 Hz. Einige Geräte unterstützen nahtlose Umstellungen der Bildwiederholrate, während bei anderen kurz ein schwarzer Bildschirm angezeigt wird, der in der Regel eine Sekunde lang anhält.
Der Hauptzweck der API besteht darin, Apps die Möglichkeit zu geben, alle unterstützten Displaywiederholraten besser zu nutzen. Wenn beispielsweise eine App ein 24‑Hz-Video wiedergibt, das setFrameRate()
aufruft, kann das Gerät die Displayaktualisierungsrate von 60 Hz auf 120 Hz ändern. Diese neue Bildwiederholrate ermöglicht eine flüssige, ruckelfreie Wiedergabe von 24‑Hz-Videos, ohne dass ein 3:2-Pulldown erforderlich ist, wie es für die Wiedergabe desselben Videos auf einem 60‑Hz-Display erforderlich wäre. Dies führt zu einer besseren User Experience
Nutzererfahrung.
Grundlegende Nutzung
Android bietet mehrere Möglichkeiten, auf Oberflächen zuzugreifen und sie zu steuern. Daher gibt es mehrere Versionen der setFrameRate()
API. Jede Version der API verwendet dieselben Parameter und funktioniert genauso wie die anderen:
Surface.setFrameRate()
SurfaceControl.Transaction.setFrameRate()
ANativeWindow_setFrameRate()
ASurfaceTransaction_setFrameRate()
Die App berücksichtigt nicht
die tatsächlich unterstützten Display-Aktualisierungsraten,
Rufen Sie dazu den folgenden Befehl auf:
Display.getSupportedModes()
,
um setFrameRate()
sicher anzurufen. Auch wenn das Gerät nur 60 Hz unterstützt, rufe setFrameRate()
mit der Framerate auf, die für deine App bevorzugt wird.
Auf Geräten, die keine bessere Übereinstimmung mit der Framerate der App haben, bleibt die aktuelle Displayaktualisierungsrate erhalten.
Wenn Sie wissen möchten, ob ein Aufruf von setFrameRate()
zu einer Änderung der Bildwiederholrate führt, registrieren Sie sich für Benachrichtigungen zu Displayänderungen. Rufen Sie dazu DisplayManager.registerDisplayListener()
oder AChoreographer_registerRefreshRateCallback()
auf.
Beim Aufrufen von setFrameRate()
ist es am besten, die genaue Framerate zu übergeben,
als das Runden auf eine ganze Zahl. Zum Beispiel beim Rendern eines Videos, das
29,97 Hz übergeben und nicht auf 30 gerundet wird, sondern 29,97.
Für Video-Apps sollte der an setFrameRate()
übergebene Kompatibilitätsparameter festgelegt werden
an Surface.FRAME_RATE_COMPATIBILITY_FIXED_SOURCE
, um einen zusätzlichen Hinweis für
die Android-Plattform, die die App verwendet, um sie an eine nicht übereinstimmende
Aktualisierungsrate des Displays. Dies führt zu Ruckeln.
In einigen Fällen sendet die Videooberfläche zwar keine Frames mehr, aber sie bleibt unverändert.
einige Zeit auf dem Bildschirm sichtbar sind. Häufige Szenarien sind die Wiedergabe
das Ende des Videos erreicht oder der Nutzer die Wiedergabe anhält. In diesen Fällen
Rufen Sie setFrameRate()
auf und setzen Sie den Framerate-Parameter auf 0, um die
Framerate auf den Standardwert zurückgesetzt. Das Löschen der Framerate-Einstellung ist nicht erforderlich, wenn die Oberfläche zerstört oder ausgeblendet wird, weil der Nutzer zu einer anderen App wechselt. Löschen Sie die Framerate-Einstellung nur, wenn die Oberfläche sichtbar bleibt, ohne verwendet zu werden.
Nicht nahtloser Wechsel der Framerate
Auf einigen Geräten kann es beim Umschalten der Aktualisierungsrate zu visuellen Unterbrechungen wie einem schwarzen
ein oder zwei Sekunden lang. Dies geschieht in der Regel bei Set-Top-Boxen, TV-Panels
und ähnliche Geräte. Standardmäßig wechselt das Android-Framework nicht den Modus
wenn der Surface.setFrameRate()
API aufgerufen, um solche optischen Unterbrechungen zu vermeiden.
Einige Nutzer bevorzugen eine visuelle Unterbrechung zu Beginn und am Ende längerer Videos. So kann die Bildwiederholrate des Displays an die Framerate des Videos angepasst werden und es werden keine Framerate-Konvertierungsartefakte wie Ruckler bei der 3:2-Pulldown-Filmwiedergabe vermieden.
Aus diesem Grund können nicht nahtlose Wechsel der Bildwiederholrate aktiviert werden, wenn sowohl der Nutzer als auch die Apps dies aktivieren:
- Nutzer: Nutzer können die Einstellung Framerate der Inhalte angleichen aktivieren.
- Apps: Wenn Sie die Funktion aktivieren möchten, können Sie
CHANGE_FRAME_RATE_ALWAYS
ansetFrameRate()
übergeben.
Wir empfehlen, für Videos mit langer Laufzeit wie Filme immer CHANGE_FRAME_RATE_ALWAYS
zu verwenden. Das liegt daran, dass der Vorteil
die Framerate des Videos überwiegt die Unterbrechung, die beim Ändern der
Aktualisierungsrate.
Weitere Empfehlungen
Beachten Sie die folgenden Empfehlungen für häufige Szenarien.
Mehrere Oberflächen
Die Android-Plattform ist darauf ausgelegt,
auf mehreren Oberflächen mit unterschiedlichen Framerate-Einstellungen. Wenn Ihre App mehrere
Oberflächen mit unterschiedlichen Frame-Rates verwenden, rufen Sie setFrameRate()
mit dem
Frame-Rate für die jeweilige Oberfläche. Auch wenn auf dem Gerät mehrere Apps
Mit dem Splitscreen-Modus oder dem Bild-im-Bild-Modus kann jede App
setFrameRate()
für ihre eigenen Oberflächen.
Die Plattform ändert sich nicht an der Framerate der App.
Auch wenn das Gerät die Framerate unterstützt, die von der App in einem Aufruf von
setFrameRate()
, es gibt Fälle, in denen das Display das Display nicht wechselt
die Aktualisierungsrate erhöhen. So kann beispielsweise eine Oberfläche mit höherer Priorität eine andere Framerate haben oder das Gerät befindet sich im Energiesparmodus, wodurch die Bildwiederholrate des Displays eingeschränkt wird, um den Akku zu schonen. Die App muss immer noch
ordnungsgemäß funktioniert, wenn das Gerät die Aktualisierungsrate des Displays nicht auf die
der Framerate der App, auch wenn das Gerät im normalen Modus wechselt.
Situation.
Die App entscheidet selbst, wie sie reagieren soll, wenn die Aktualisierungsrate des Displays
nicht mit der Framerate der App übereinstimmt. Bei Videos ist die Framerate auf die des Quellvideos festgelegt. Für die Wiedergabe des Videoinhalts ist ein Drop-down-Menü erforderlich. Ein Spiel kann stattdessen versuchen, mit der Bildwiederholrate des Displays ausgeführt zu werden, anstatt bei der bevorzugten Framerate zu bleiben. Die App darf den Wert, den sie an setFrameRate()
übergibt, nicht basierend auf der Funktionsweise der Plattform ändern. Sie sollte auf die bevorzugte Framerate der App eingestellt bleiben, unabhängig davon, wie die App Fälle behandelt, in denen sich die Plattform nicht an die Anfrage der App anpasst. So hat die Plattform die richtigen Informationen, um bei einer Änderung der Gerätebedingungen zur Verwendung zusätzlicher Displayaktualisierungsraten zur bevorzugten Framerate der App zu wechseln.
Wenn die App nicht oder nicht mit der Bildwiederholrate des Displays ausgeführt wird, sollte sie für jeden Frame Präsentationszeitstempel angeben. Dazu kann einer der Mechanismen der Plattform zum Festlegen von Präsentationszeitstempeln verwendet werden:
Wenn Sie diese Zeitstempel verwenden, kann die Plattform auch keinen App-Frame präsentieren was zu unnötigem Rumpf führen würde. Die korrekte Verwendung von Zeitstempeln für die Frame-Darstellung ist etwas schwierig. Informationen zu Spielen findest du in unserer Leitfaden zur Taktung von Frames findest du weitere Informationen zur Vermeidung von Rauschen. Außerdem kannst du Android Frame Pacing Library.
In einigen Fällen wechselt die Plattform zu einem Vielfachen der Framerate der App.
angegeben in setFrameRate()
. Eine App ruft beispielsweise setFrameRate()
mit 60 Hz auf und das Gerät schaltet das Display auf 120 Hz um. Ein Grund dafür,
tritt auf, wenn eine andere App
eine Oberfläche mit einer Framerate von 24 Hz hat. In diesem Fall können sowohl die 60‑Hz- als auch die 24‑Hz-Oberfläche ohne Pulldown ausgeführt werden, wenn das Display mit 120 Hz betrieben wird.
Wenn der Bildschirm mit einem Vielfachen der Framerate der App ausgeführt wird, zeigt die App sollten Präsentationszeitstempel für jeden Frame angeben, um unnötige Richtig schlecht. Bei Spielen ist die Android Frame Pacing-Bibliothek hilfreich, um Zeitstempel für die Frame-Darstellung korrekt festzulegen.
setFrameRate() im Vergleich zu preferredDisplayModeId
WindowManager.LayoutParams.preferredDisplayModeId
ist eine weitere Möglichkeit, wie Apps ihre Framerate an die Plattform senden können. Einige
Apps nur die Aktualisierungsrate des Displays ändern, statt andere
Einstellungen für den Anzeigemodus
wie z. B. die Bildschirmauflösung. Verwenden Sie im Allgemeinen setFrameRate()
anstelle von preferredDisplayModeId
. Die Funktion setFrameRate()
ist einfacher zu verwenden, da die App nicht die Liste der Anzeigemodi durchsuchen muss, um einen Modus mit einer bestimmten Framerate zu finden.
setFrameRate()
bietet der Plattform mehr Möglichkeiten, eine kompatible
in Szenarien mit mehreren Oberflächen, die auf
unterschiedliche Frame-Rates. Stellen Sie sich beispielsweise ein Szenario vor, bei dem zwei Apps
auf einem Pixel 4 im Splitscreen-Modus, wobei eine App ein 24-Hz-Video abspielt
und eine scrollbare Liste. Pixel 4 unterstützt zwei
Display-Aktualisierungsraten: 60 Hz und 90 Hz. Bei Verwendung der preferredDisplayModeId
API muss für die Videofläche entweder 60 Hz oder 90 Hz ausgewählt werden. Wenn setFrameRate()
mit 24 Hz aufgerufen wird, gibt die Videofläche der Plattform mehr Informationen zur Framerate des Quellvideos. So kann die Plattform 90 Hz für die Displayaktualisierungsrate auswählen, was in diesem Szenario besser ist als 60 Hz.
Es gibt jedoch Szenarien, in denen preferredDisplayModeId
verwendet werden sollte
statt setFrameRate()
. Beispiel:
- Wenn die App die Auflösung oder andere Einstellungen des Anzeigemodus ändern soll, verwenden Sie
preferredDisplayModeId
. - Die Plattform wechselt nur als Reaktion auf einen Aufruf von
setFrameRate()
, wenn der Moduswechsel leicht ist, dies jedoch unwahrscheinlich ist für die Nutzenden erkennbar sind. Wenn die App die Displayaktualisierung bevorzugt, auch wenn ein intensiver Moduswechsel erforderlich ist (z. B. auf einem Android TV-Gerät). Gerät), verwenden SiepreferredDisplayModeId
. - Bei Apps, die das Display nicht mit einer Framerate ausführen können, die ein Vielfaches der Framerate der App ist, müssen für jeden Frame Präsentationszeitstempel festgelegt werden. In diesen Fällen sollte
preferredDisplayModeId
verwendet werden.
setFrameRate() im Vergleich zu PreferredRefreshRate
WindowManager.LayoutParams#preferredRefreshRate
legt eine bevorzugte Frame-Rate im App-Fenster fest und die Rate gilt
für alle Oberflächen des Fensters. Die App sollte die bevorzugte Framerate unabhängig von den unterstützten Aktualisierungsraten des Geräts angeben, ähnlich wie bei setFrameRate()
, um dem Scheduler einen besseren Hinweis auf die beabsichtigte Framerate der App zu geben.
preferredRefreshRate
wird für Oberflächen ignoriert, die setFrameRate()
verwenden. Verwenden Sie nach Möglichkeit setFrameRate()
.
preferredRefreshRate im Vergleich zu preferredDisplayModeId
Wenn Apps nur die bevorzugte Aktualisierungsrate ändern möchten, empfiehlt sich die Verwendung von
preferredRefreshRate
statt preferredDisplayModeId
.
Zu häufiges Aufrufen von setFrameRate() vermeiden
Der setFrameRate()
-Aufruf ist zwar nicht sehr leistungsintensiv, Apps sollten setFrameRate()
jedoch nicht in jedem Frame oder mehrmals pro Sekunde aufrufen. Aufrufe an setFrameRate()
führen wahrscheinlich zu einer Änderung des
Aktualisierungsrate des Bildschirms, was zu einem Rückgang der Frame während des Übergangs führen kann.
Sie sollten die richtige Framerate im Voraus ermitteln und setFrameRate()
einmal aufrufen.
Nutzung für Spiele und andere Apps ohne Video
Videos sind der primäre Anwendungsfall für die setFrameRate()
API, sie kann aber auch für andere Apps verwendet werden. Ein Spiel, das beispielsweise nicht schneller als 60 Hz laufen soll, um den Stromverbrauch zu senken und längere Spielsitzungen zu ermöglichen, kann Surface.setFrameRate(60, Surface.FRAME_RATE_COMPATIBILITY_DEFAULT)
aufrufen. In dieser
Geräte, die standardmäßig mit 90 Hz laufen, stattdessen mit 60 Hz, während der
das Spiel aktiv ist. Dadurch wird verhindert, dass der Nutzer ruckelt, wenn das Spiel
das Spiel bei 60 Hz, das Display bei 90 Hz.
Verwendung von FRAME_RATE_COMPATIBILITY_FIXED_SOURCE
FRAME_RATE_COMPATIBILITY_FIXED_SOURCE
ist nur für Video-Apps vorgesehen. Für
nicht für Videos: FRAME_RATE_COMPATIBILITY_DEFAULT
verwenden.
Strategie zum Ändern der Framerate auswählen
- Wenn Apps mit langer Laufzeit wie z. B.
Filme,
setFrameRate(
fps, FRAME_RATE_COMPATIBILITY_FIXED_SOURCE, CHANGE_FRAME_RATE_ALWAYS)
anrufen wobei fps für die Frame-Rate des Videos steht. - Wir raten dringend davon ab, in Apps
setFrameRate()
mitCHANGE_FRAME_RATE_ALWAYS
aufzurufen, wenn die Videowiedergabe voraussichtlich nur wenige Minuten dauert.
Beispielintegration für Apps zur Videowiedergabe
Wir empfehlen die folgenden Schritte zum Integrieren von Schaltern für die Aktualisierungsrate in Apps zur Videowiedergabe:
- Legen Sie die
changeFrameRateStrategy
fest:- Wenn Sie ein Video mit langer Laufzeit, z. B. einen Film, abspielen möchten, verwenden Sie
MATCH_CONTENT_FRAMERATE_ALWAYS
. - Wenn ein kurzes Video wie ein Filmtrailer wiedergegeben wird, verwenden Sie
CHANGE_FRAME_RATE_ONLY_IF_SEAMLESS
.
- Wenn Sie ein Video mit langer Laufzeit, z. B. einen Film, abspielen möchten, verwenden Sie
- Wenn
changeFrameRateStrategy
=CHANGE_FRAME_RATE_ONLY_IF_SEAMLESS
ist, fahren Sie mit Schritt 4 fort. - Prüfen Sie, ob ein Wechsel der Aktualisierungsrate bei einer nicht nahtlosen Aktualisierung bevorsteht.
dass diese beiden Fakten wahr sind:
- Ein nahtloser Moduswechsel von der aktuellen Bildwiederholrate (nennen wir sie C) zur Framerate des Videos (nennen wir sie V) ist nicht möglich. Dadurch wird
wenn C und V unterschiedlich sind und
Display.getMode().getAlternativeRefreshRates
kein Vielfaches von V enthält. - Der Nutzer hat die Option für nicht nahtlose Änderungen der Bildwiederholrate aktiviert. Sie können das prüfen, indem Sie sehen, ob
DisplayManager.getMatchContentFrameRateUserPreference
MATCH_CONTENT_FRAMERATE_ALWAYS
zurückgibt.
- Ein nahtloser Moduswechsel von der aktuellen Bildwiederholrate (nennen wir sie C) zur Framerate des Videos (nennen wir sie V) ist nicht möglich. Dadurch wird
wenn C und V unterschiedlich sind und
- Wenn die Umstellung nahtlos erfolgen soll, gehen Sie so vor:
setFrameRate
anrufen und übergeben esfps
,FRAME_RATE_COMPATIBILITY_FIXED_SOURCE
, undchangeFrameRateStrategy
, wobeifps
die Framerate des Videos ist.- Videowiedergabe starten
- Wenn eine Änderung des nicht nahtlosen Modus bevorsteht, gehen Sie so vor:
- Zeigen Sie die UX, um den Nutzer zu benachrichtigen. Wir empfehlen Ihnen, in Schritt 5.d eine Möglichkeit zu implementieren, mit der Nutzer diese UX schließen und die zusätzliche Verzögerung überspringen können. Das liegt daran, dass die empfohlene Verzögerung bei Displays mit kürzeren Schaltzeiten länger ist als erforderlich.
setFrameRate
anrufen und übergeben esfps
,FRAME_RATE_COMPATIBILITY_FIXED_SOURCE
, undCHANGE_FRAME_RATE_ALWAYS
Dabei istfps
die Framerate des Videos.- Warten Sie, bis die
onDisplayChanged
Callback des Nutzers an. - Warten Sie zwei Sekunden, bis der Moduswechsel abgeschlossen ist.
- Videowiedergabe starten
Der Pseudocode, der ausschließlich den nahtlosen Wechsel unterstützt, lautet wie folgt:
SurfaceControl.Transaction transaction = new SurfaceControl.Transaction();
transaction.setFrameRate(surfaceControl,
contentFrameRate,
FRAME_RATE_COMPATIBILITY_FIXED_SOURCE,
CHANGE_FRAME_RATE_ONLY_IF_SEAMLESS);
transaction.apply();
beginPlayback();
Der oben beschriebene Pseudocode zur Unterstützung des nahtlosen und nahtlosen Wechsels lautet wie folgt:
SurfaceControl.Transaction transaction = new SurfaceControl.Transaction();
if (isSeamlessSwitch(contentFrameRate)) {
transaction.setFrameRate(surfaceControl,
contentFrameRate,
FRAME_RATE_COMPATIBILITY_FIXED_SOURCE,
CHANGE_FRAME_RATE_ONLY_IF_SEAMLESS);
transaction.apply();
beginPlayback();
} else if (displayManager.getMatchContentFrameRateUserPreference()
== MATCH_CONTENT_FRAMERATE_ALWAYS) {
showRefreshRateSwitchUI();
sleep(shortDelaySoUserSeesUi);
displayManager.registerDisplayListener(…);
transaction.setFrameRate(surfaceControl,
contentFrameRate,
FRAME_RATE_COMPATIBILITY_FIXED_SOURCE,
CHANGE_FRAME_RATE_ALWAYS);
transaction.apply();
waitForOnDisplayChanged();
sleep(twoSeconds);
hideRefreshRateSwitchUI();
beginPlayback();
}