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 Aktualisierungsrate eines Displays unterstützt. normalerweise bei 60 Hz, aber das hat sich geändert. Viele Geräte unterstützen jetzt zusätzliche Aktualisierungsraten wie 90 Hz oder 120 Hz. Einige Geräte unterstützen eine nahtlose Aktualisierungsrate. während andere kurz einen schwarzen Bildschirm zeigen (normalerweise eine Sekunde lang).
Der Hauptzweck der API besteht darin, Apps zu ermöglichen, alle
die unterstützten Aktualisierungsraten für das Display. Beispiel: Eine App spielt ein 24-Hz-Video ab.
über die setFrameRate()
aufgerufen wird, kann das dazu führen, dass auf dem Gerät das Display gewechselt wird.
von 60 Hz auf 120 Hz aktualisiert. Die neue Aktualisierungsrate ermöglicht
ruckelfreie Wiedergabe von 24-Hz-Videos, ohne dass ein 3:2-Pulldown-Menü erforderlich ist.
erforderlich, um dasselbe Video auf einem 60-Hz-Display wiederzugeben. Dies führt zu einer besseren User Experience
Nutzererfahrung.
Grundlegende Nutzung
Android bietet verschiedene Möglichkeiten,
auf Oberflächen zuzugreifen und diese zu steuern,
Versionen der setFrameRate()
API Jede Version der API verwendet den
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. Selbst wenn das Gerät nur
60 Hz unterstützt, rufe setFrameRate()
mit der von deiner App bevorzugten Framerate auf.
Geräte, die nicht genau an die Framerate der App angepasst sind, bleiben mit
die aktuelle Aktualisierungsrate des Displays.
Um zu sehen, ob ein Aufruf von setFrameRate()
zu einer Änderung der Displayaktualisierung führt
und melden Sie sich für Benachrichtigungen zu Displayänderungen an, indem Sie
DisplayManager.registerDisplayListener()
oder AChoreographer_registerRefreshRateCallback()
.
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 wird bei 29,97 ausgegeben und nicht auf 30 gerundet.
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. Framerate-Einstellung löschen
ist nicht notwendig, wenn die Oberfläche zerstört oder
weil der Nutzer zu einer anderen App wechselt. Framerate löschen
wenn die Oberfläche sichtbar bleibt und nicht verwendet wird.
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 Nutzende bevorzugen eine visuelle Unterbrechung am Anfang und am Ende von längeren Videos. Dadurch wird die Aktualisierungsrate des Bildschirms Video-Framerate ändern und Framerate-Konvertierungsartefakte wie 3:2 vermeiden Pulldown-Menü zur Wiedergabe des Films.
Aus diesem Grund kann der Wechsel der nicht nahtlosen Aktualisierungsrate aktiviert werden, wenn sowohl die Opt-in für Nutzer und Apps:
- Nutzer: Nutzer können die Option Framerate für Inhalte anpassen aktivieren, um sie zu aktivieren. Einstellung.
- Apps: Für die Aktivierung dürfen Apps den
CHANGE_FRAME_RATE_ALWAYS
insetFrameRate()
.
Wir empfehlen, immer CHANGE_FRAME_RATE_ALWAYS
zu verwenden
für Videos mit langer Ausführungszeit (z. B. Filme). Das liegt daran, dass der Vorteil
die Framerate des Videos überwiegt die Unterbrechung, die beim Ändern der
Aktualisierungsrate.
Weitere Empfehlungen
Beachten Sie bei häufigen Szenarien die folgenden Empfehlungen.
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. Beispielsweise kann eine Oberfläche mit höherer Priorität
oder das Gerät befindet sich möglicherweise im Energiesparmodus (Einstellung
Einschränkung der Aktualisierungsrate des Displays, 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 fest auf die von
Quellvideo und Pulldown-Menü zur Anzeige des Video-Contents erforderlich. A
wird das Spiel stattdessen mit der Aktualisierungsrate des Displays
und dabei die bevorzugte Frame-Rate beibehalten. Der Wert sollte von der App nicht geändert werden.
je nach Funktion der Plattform an setFrameRate()
übergibt. Sie sollte eingestellt bleiben
die bevorzugte Framerate der App anpassen, unabhängig davon, wie die App mit Fällen umgeht,
die Plattform sich nicht
an die Anforderungen der App anpasst. Auf diese Weise können Sie
Bedingungen geändert werden, sodass zusätzliche Aktualisierungsraten für das Display verwendet werden können.
Plattform die richtigen Informationen hat, um zum bevorzugten Frame der App zu wechseln
zu zahlen.
Falls die App nicht mit der Aktualisierungsrate des Displays ausgeführt werden kann, zeigt die App Präsentationszeitstempel für jeden Frame angeben. Verwenden Sie dazu einen der Mechanismen der Plattform zum Festlegen von Präsentationszeitstempeln:
Wenn Sie diese Zeitstempel verwenden, kann die Plattform auch keinen App-Frame präsentieren was zu unnötigem Rumpf führen würde. Richtige Verwendung des Frames die Zeitstempel von Präsentationen ist ein bisschen kompliziert. 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 kann z. B. setFrameRate()
aufrufen
mit 60 Hz 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
Bei einem Display mit 120 Hz sind sowohl die 60-Hz-Oberfläche als auch
24-Hz-Oberfläche ohne Pull-down-Verfahren.
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 hilft die Android Frame Pacing Library, die Zeitstempel der Frame-Präsentation.
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()
statt preferredDisplayModeId
. Das setFrameRate()
ist einfacher zu nutzen, da die App nicht die
der Anzeigemodi, 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. Mit der preferredDisplayModeId
API
wird gezwungen, entweder 60 Hz oder 90 Hz auszuwählen. Durch den Anruf
setFrameRate()
mit 24 Hz bietet die Videooberfläche der Plattform mehr
zur Framerate des Quellvideos, sodass die Plattform
wählen Sie für die Aktualisierungsrate des Displays 90 Hz aus. Das ist hier besser als 60 Hz
Szenario.
Es gibt jedoch Szenarien, in denen preferredDisplayModeId
verwendet werden sollte
statt setFrameRate()
. Beispiel:
- Wenn die App die Auflösung oder andere Einstellungen
für den Anzeigemodus ändern möchte,
preferredDisplayModeId
verwenden. - 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
. - Apps, die den Bildschirm nicht verarbeiten können, der in einem Vielfachen der App-Frames ausgeführt wird
bei dem für jeden Frame ein Zeitstempel für die Präsentation festgelegt werden muss,
preferredDisplayModeId
verwenden.
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. In der App sollte die bevorzugte
Framerate unabhängig von den unterstützten Bildwiederholraten des Geräts, ähnlich wie
setFrameRate()
, um dem Planer einen besseren Eindruck davon zu vermitteln,
Frame-Rate.
preferredRefreshRate
wird bei Oberflächen, die setFrameRate()
verwenden, ignoriert. In
Verwende nach Möglichkeit allgemein setFrameRate()
.
bevorzugte Aktualisierungsrate 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
Obwohl der setFrameRate()
-Aufruf in Bezug auf die Leistung nicht sehr teuer ist,
Apps sollten setFrameRate()
nicht in jedem Frame oder mehrmals pro Frame aufrufen.
2. 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 dann
setFrameRate()
einmal.
Nutzung für Spiele und andere Apps ohne Video
Video ist zwar der primäre Anwendungsfall für die setFrameRate()
API, kann aber auch
die für andere Apps verwendet werden. Beispiel: Ein Spiel, das nicht mehr als
60 Hz (um den Stromverbrauch zu reduzieren und längere Spielsitzungen zu erreichen) kann Anrufe
Surface.setFrameRate(60, Surface.FRAME_RATE_COMPATIBILITY_DEFAULT)
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, Apps
setFrameRate()
mitCHANGE_FRAME_RATE_ALWAYS
aufzurufen wenn die Videowiedergabe höchstens mehrere Minuten dauern soll.
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: <ph type="x-smartling-placeholder">- </ph>
- Wenn Sie ein Video mit langer Laufzeit, z. B. einen Film, abspielen möchten, verwenden Sie
MATCH_CONTENT_FRAMERATE_ALWAYS
. - Verwende
CHANGE_FRAME_RATE_ONLY_IF_SEAMLESS
, wenn du ein kurzes Video abspielst, z. B. einen Move-Trailer
- 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:
<ph type="x-smartling-placeholder">
- </ph>
- Bei der aktuellen Aktualisierungsrate ist ein Wechsel in den nahtlosen Modus nicht möglich.
C) zur Framerate des Videos hinzu (wir nennen es V). Dadurch wird
wenn C und V unterschiedlich sind und
Display.getMode().getAlternativeRefreshRates
kein Vielfaches von V enthält. - Der Nutzer hat der nahtlosen Änderung der Aktualisierungsrate zugestimmt. Sie können
indem Sie prüfen, ob
DisplayManager.getMatchContentFrameRateUserPreference
gibt zurück:MATCH_CONTENT_FRAMERATE_ALWAYS
- Bei der aktuellen Aktualisierungsrate ist ein Wechsel in den nahtlosen Modus nicht möglich.
C) zur Framerate des Videos hinzu (wir nennen es V). Dadurch wird
wenn C und V unterschiedlich sind und
- Wenn der Wechsel reibungslos verläuft, gehen Sie so vor:
<ph type="x-smartling-placeholder">
- </ph>
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:
<ph type="x-smartling-placeholder">
- </ph>
- Zeigen Sie die UX, um den Nutzer zu benachrichtigen. Wir empfehlen, eine Methode zu implementieren, Nutzende zu schließen und die zusätzliche Verzögerung in Schritt 5.d zu überspringen. Dies ist da die von uns empfohlene Verzögerung auf Bildschirmen größer als erforderlich ist, schnellere Wechselzeiten aufweisen.
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();
}