La API de velocidad de fotogramas permite que las apps informen a la plataforma de Android el fotograma deseado y está disponible en apps orientadas a Android 11 (nivel de API 30) o versiones posteriores. Tradicionalmente, la mayoría de los dispositivos admite solo una frecuencia de actualización de pantalla, normalmente, 60 Hz, pero esto ha ido cambiando. Muchos dispositivos ahora admiten frecuencias de actualización, como 90 Hz o 120 Hz. Algunos dispositivos admiten una frecuencia de actualización fluida interruptores, mientras que otros muestran brevemente una pantalla negra que suele durar un segundo.
El objetivo principal de la API es permitir que las apps aprovechen mejor todas
las frecuencias de actualización de pantalla admitidas. Por ejemplo, una app que reproduce un video de 24 Hz
que llame a setFrameRate()
podría provocar que el dispositivo cambie de pantalla
frecuencia de actualización de 60 Hz a 120 Hz. Esta nueva frecuencia de actualización permite
Reproducción de video de 24 Hz sin sacudidas, sin necesidad de aplicar despliegue de 3:2.
para reproducir el mismo video en una pantalla de 60 Hz. Esto da como resultado una mejor experiencia
una experiencia fluida a los desarrolladores.
Uso básico
Android expone varias formas de acceder y controlar superficies, de modo que hay
varias versiones de la API de setFrameRate()
. Cada versión de la API toma la
con los mismos parámetros y funciona igual que los demás:
Surface.setFrameRate()
SurfaceControl.Transaction.setFrameRate()
ANativeWindow_setFrameRate()
ASurfaceTransaction_setFrameRate()
La app no necesita considerar las frecuencias reales de actualización de pantalla admitidas,
que se puede obtener llamando
Display.getSupportedModes()
:
para llamar de forma segura a setFrameRate()
. Por ejemplo, aunque el dispositivo solo
admite 60 Hz, llama a setFrameRate()
con la velocidad de fotogramas que prefiera tu app.
Los dispositivos que no tengan una mejor concordancia con la velocidad de fotogramas de la app permanecerán como
la frecuencia de actualización actual de la pantalla.
Para ver si una llamada a setFrameRate()
genera un cambio en la actualización de la pantalla
frecuencia, registra para recibir notificaciones de cambio de pantalla llamando
DisplayManager.registerDisplayListener()
o AChoreographer_registerRefreshRateCallback()
.
Cuando se llama a setFrameRate()
, es mejor pasar la velocidad de fotogramas exacta en lugar
redondear a un número entero. Por ejemplo, si renderizas un video grabado en
29.97 Hz, pasa 29.97 en lugar de redondear a 30.
En el caso de las apps de video, se debe establecer el parámetro de compatibilidad que se pasa a setFrameRate()
a Surface.FRAME_RATE_COMPATIBILITY_FIXED_SOURCE
para darle una pista adicional a
la plataforma de Android que la app usará desplegables para adaptarse a una
la frecuencia de actualización de la pantalla (que hará que se sacude).
En algunos casos, la plataforma del video dejará de enviar fotogramas, pero permanecerá
visible en la pantalla durante un tiempo. Las situaciones comunes incluyen cuando la reproducción
Llega al final del video o cuando el usuario pausa la reproducción. En estos casos,
llama a setFrameRate()
con el parámetro de velocidad de fotogramas establecido en 0 para borrar la latencia
velocidad de fotogramas al valor predeterminado. Borrando la configuración de velocidad de fotogramas
de esta manera no es necesaria cuando se destruye la superficie,
oculto porque el usuario cambia a otra aplicación. Borra la velocidad de fotogramas
configuración solo cuando la superficie permanece visible sin que se use.
Interruptor de velocidad de fotogramas ininterrumpido
En algunos dispositivos, el cambio de frecuencia de actualización puede tener interrupciones visuales, como una notificación
pantalla durante uno o dos segundos. Esto suele ocurrir en decodificadores, paneles de TV,
y dispositivos similares. De forma predeterminada, el framework de Android no cambia de modo
cuando el elemento Surface.setFrameRate()
para evitar estas interrupciones visuales.
Algunos usuarios prefieren una interrupción visual al principio y el final de los videos más largos. Esto permite que coincida la frecuencia de actualización de la pantalla la velocidad de fotogramas del video y evitar artefactos de conversión de velocidad de fotogramas como 3:2 sacudida desplegable para reproducir la película.
Por esta razón, los interruptores de frecuencia de actualización que no sean fluidos pueden habilitarse si tanto aceptación del usuario y las apps:
- Usuarios: Para habilitar esta opción, los usuarios pueden habilitar la opción Ajustar la velocidad de fotogramas del contenido. del lugar.
- Apps: Para habilitar la opción, las apps pueden pasar
CHANGE_FRAME_RATE_ALWAYS
asetFrameRate()
.
Te recomendamos que siempre uses CHANGE_FRAME_RATE_ALWAYS
para videos de larga duración, como películas. Esto se debe a que el beneficio de hacer coincidir
la velocidad de fotogramas supera la interrupción que se produce al cambiar la
frecuencia de actualización.
Recomendaciones adicionales
Sigue estas recomendaciones para situaciones comunes.
Varias superficies
La plataforma de Android se diseñó para manejar correctamente situaciones en las que hay
en varias plataformas con diferentes configuraciones de velocidad de fotogramas. Cuando tu app tiene varias
plataformas con distintas velocidades de fotogramas, llama a setFrameRate()
con la
la velocidad de fotogramas de cada superficie. Aunque el dispositivo ejecute varias apps en
una vez, con el modo de pantalla dividida o pantalla en pantalla, cada app puede llamar
setFrameRate()
para sus propias plataformas
La plataforma no cambia a la velocidad de fotogramas de la app
Incluso si el dispositivo admite la velocidad de fotogramas que la app especifica en una llamada a
setFrameRate()
, hay casos en los que el dispositivo no cambia la pantalla a
esa frecuencia de actualización. Por ejemplo, una superficie de mayor prioridad puede tener un valor
velocidad de fotogramas o que el dispositivo esté en modo ahorro de batería (configurar una
en la frecuencia de actualización de la pantalla para conservar la batería). La aplicación debe seguir
funcionará correctamente cuando el dispositivo no cambie la frecuencia de actualización de la pantalla al
la velocidad de fotogramas de la app, incluso si el dispositivo cambia según lo normal
a las circunstancias.
Depende de la app decidir cómo responder cuando la frecuencia de actualización de la pantalla
no coincide con la velocidad de fotogramas de la app. Para los videos, la velocidad de fotogramas se fija en la del
el video de origen y se solicitará un menú desplegable para mostrar el contenido del video. R
el juego puede optar por intentar ejecutarse a la frecuencia de actualización de la pantalla en lugar de
y mantenga su velocidad de fotogramas preferida. La app no debería cambiar su valor
pase a setFrameRate()
según lo que haga la plataforma. Debería permanecer fija
según la velocidad de fotogramas preferida de la app, sin importar cómo la app maneja los casos en los que
la plataforma no se ajusta para coincidir con la solicitud de la app. De esta manera, si el dispositivo
las condiciones cambian para permitir que se usen frecuencias de actualización de pantalla adicionales, el
plataforma tenga la información correcta para cambiar al fotograma preferido de la app
tasa.
En los casos en que la app no se ejecute o no pueda ejecutarse a la frecuencia de actualización de la pantalla, la app deberías especificar marcas de tiempo de presentación para cada marco mecanismos de la plataforma para establecer marcas de tiempo de presentación:
Si usas estas marcas de tiempo, la plataforma también dejará de presentar un fotograma de la app. tempranamente, lo que generaría una sacudida innecesaria. Uso correcto del marco las marcas de tiempo de presentación es un poco complicada. Para juegos, consulta nuestra guía de ritmo de fotogramas para obtener más información sobre cómo evitar que te sacudas y considera utilizar el Biblioteca de Android Frame Pacing
En algunos casos, la plataforma puede cambiar a un múltiplo de la velocidad de fotogramas de la app
especificadas en setFrameRate()
. Por ejemplo, una app puede llamar a setFrameRate()
con 60 Hz, y el dispositivo puede cambiar la pantalla a 120 Hz. Una de las razones por las que esto podría
sucede cuando otra app tiene una superficie con
una configuración de velocidad de fotogramas de 24 Hz. En
en ese caso, ejecutar la pantalla a 120 Hz permitirá que tanto la superficie de
Se trata de una superficie de 24 Hz que se ejecuta sin necesidad de bajar el brazo.
Cuando la pantalla se ejecuta a un múltiplo de la velocidad de fotogramas de la app, la app debes especificar marcas de tiempo de presentación en cada fotograma para evitar sacudir. En el caso de los juegos, la biblioteca de Android Frame Pacing es útil para la configuración de marcas de tiempo de presentación de marcos.
setFrameRate() frente a PreferredDisplayModeId
WindowManager.LayoutParams.preferredDisplayModeId
es otra forma en que las apps pueden indicar su velocidad de fotogramas a la plataforma. Algunos
las apps solo quieren cambiar la frecuencia de actualización de la pantalla en lugar de cambiar otras
del modo de visualización, como la resolución. En general, usa
setFrameRate()
en lugar de preferredDisplayModeId
. El setFrameRate()
es más fácil de usar porque la app no necesita buscar en la
de modos de visualización para encontrar un modo con una velocidad de fotogramas específica.
setFrameRate()
le da a la plataforma más oportunidades de elegir una
velocidad de fotogramas en situaciones en las que hay varias plataformas que se ejecutan en
a diferentes velocidades de fotogramas. Por ejemplo, imagina una situación en la que dos aplicaciones
si se ejecuta en el modo de pantalla dividida en un Pixel 4, en el que una app reproduce un video de 24 Hz
y la otra le muestra al usuario una lista desplazable. El Pixel 4 admite dos
frecuencias de actualización de la pantalla: 60 Hz y 90 Hz. Con la API de preferredDisplayModeId
,
la superficie del video selecciona 60 Hz o 90 Hz. Llamando
setFrameRate()
con 24 Hz, la superficie de video le brinda más a la plataforma
información sobre la velocidad de fotogramas del video de origen, lo que permite que la plataforma
elige 90 Hz para la frecuencia de actualización de la pantalla, que es mejor que 60 Hz en este
situación.
Sin embargo, hay situaciones en las que se debe usar preferredDisplayModeId
.
en lugar de setFrameRate()
, como se muestra a continuación:
- Si la app quiere cambiar la resolución o alguna otra configuración del modo de visualización, haz lo siguiente:
usa
preferredDisplayModeId
. - La plataforma solo cambiará los modos de visualización en respuesta a una llamada a
setFrameRate()
si el interruptor de modo es ligero y es poco probable que lo sea notorio para el usuario. Si la app prefiere cambiar la actualización de la pantalla incluso si requiere un cambio de modo pesado (por ejemplo, en un dispositivo Android TV dispositivo), usapreferredDisplayModeId
. - Apps que no pueden controlar la pantalla ejecutándose en un múltiplo del fotograma de la app
de presentación, que requiere configurar marcas de tiempo de presentación en cada fotograma,
usa
preferredDisplayModeId
.
setFrameRate() frente a PreferredRefreshRate
WindowManager.LayoutParams#preferredRefreshRate
establece una velocidad de fotogramas preferida en la ventana de la app y la velocidad es aplicable
a todas las superficies dentro de la ventana. La app debe especificar su preferencia
velocidad de fotogramas, independientemente de la frecuencia de actualización que admita el dispositivo, similar a
setFrameRate()
, para darle al programador una mejor pista de la app
velocidad de fotogramas.
preferredRefreshRate
se ignora para plataformas que usan setFrameRate()
. En
usa setFrameRate()
si es posible.
PreferredRefreshRate frente a PreferredDisplayModeId
Si las apps solo quieren cambiar la frecuencia de actualización preferida, es preferible usar
preferredRefreshRate
, en lugar de preferredDisplayModeId
.
Cómo evitar llamar a setFrameRate() con demasiada frecuencia
Aunque la llamada a setFrameRate()
no es muy costosa en términos de rendimiento,
Las apps deben evitar llamar a setFrameRate()
cada fotograma o varias veces por
por segundo. Es probable que las llamadas a setFrameRate()
generen un cambio en el
la frecuencia de actualización de la pantalla, lo que puede provocar una caída de fotogramas durante la transición.
Debes determinar la velocidad de fotogramas correcta de antemano y llamar
setFrameRate()
una vez.
Uso para juegos y otras apps que no son de video
Si bien el video es el caso de uso principal de la API de setFrameRate()
, se puede
para otras apps. Por ejemplo, para un juego cuya ejecución no se debe superar
60 Hz (para reducir el consumo de energía y lograr sesiones de juego más largas) puede llamar
Surface.setFrameRate(60, Surface.FRAME_RATE_COMPATIBILITY_DEFAULT)
En este
Por eso, un dispositivo que funciona a 90 Hz de forma predeterminada lo hará a 60 Hz, mientras que
el juego está activo, lo que evitará el sacudón que se generaría si el
el juego se ejecutó a 60 Hz y la pantalla a 90 Hz.
Uso de FRAME_RATE_COMPATIBILITY_FIXED_SOURCE
FRAME_RATE_COMPATIBILITY_FIXED_SOURCE
está diseñado únicamente para apps de video. Para
para uso que no sea de video, usa FRAME_RATE_COMPATIBILITY_DEFAULT
.
Cómo elegir una estrategia para cambiar la velocidad de fotogramas
- Recomendamos que las aplicaciones, al mostrar videos de larga duración, como
películas, llama a
setFrameRate(
FPS, FRAME_RATE_COMPATIBILITY_FIXED_SOURCE, CHANGE_FRAME_RATE_ALWAYS)
donde fps es la velocidad de fotogramas del video. - Te recomendamos que no uses las apps que llamen a
setFrameRate()
conCHANGE_FRAME_RATE_ALWAYS
cuando esperas que la reproducción de un video dure varios minutos o menos.
Ejemplo de integración para apps de reproducción de video
Te recomendamos que sigas estos pasos para integrar los cambios de frecuencia de actualización en las apps de reproducción de video:
- Decide el
changeFrameRateStrategy
:- Si reproduces un video de larga duración, como una película, usa
MATCH_CONTENT_FRAMERATE_ALWAYS
. - Si reproduces un video corto, como un avance en movimiento, usa
CHANGE_FRAME_RATE_ONLY_IF_SEAMLESS
.
- Si reproduces un video de larga duración, como una película, usa
- Si el
changeFrameRateStrategy
esCHANGE_FRAME_RATE_ONLY_IF_SEAMLESS
, ve al paso 4. - Detecta si está a punto de ocurrir un cambio de frecuencia de actualización no fluido mediante la
que los dos hechos son verdaderos:
- El cambio de modo fluido no es posible desde la frecuencia de actualización actual (veamos
C) a la velocidad de fotogramas del video (queremos V). Si confirmas esta acción,
sería el caso si C y V son diferentes y
Display.getMode().getAlternativeRefreshRates
no contiene un múltiplo de V. - El usuario habilitó los cambios de frecuencia de actualización constantes. Puedes detectar
esto verificando si
DisplayManager.getMatchContentFrameRateUserPreference
muestraMATCH_CONTENT_FRAMERATE_ALWAYS
- El cambio de modo fluido no es posible desde la frecuencia de actualización actual (veamos
C) a la velocidad de fotogramas del video (queremos V). Si confirmas esta acción,
sería el caso si C y V son diferentes y
- Si el cambio va a ser fluido, haz lo siguiente:
- Llama a
setFrameRate
y pasarlofps
,FRAME_RATE_COMPATIBILITY_FIXED_SOURCE
, ychangeFrameRateStrategy
, dondefps
es la velocidad de fotogramas del video. - Iniciar reproducción de video
- Llama a
- Si está por ocurrir un cambio de modo continuo, haz lo siguiente:
- Mostrar UX para notificar al usuario Ten en cuenta que recomendamos implementar una forma de que el usuario descarte esta UX y omita el retraso adicional en el paso 5.d. Este es porque el retraso recomendado es mayor que el necesario en pantallas que presentan tiempos de cambio más rápidos.
- Llama a
setFrameRate
y pasarlofps
,FRAME_RATE_COMPATIBILITY_FIXED_SOURCE
, yCHANGE_FRAME_RATE_ALWAYS
, dondefps
es la velocidad de fotogramas del video. - Espera a que aparezca
onDisplayChanged
. devolución de llamada. - Espera 2 segundos para que se complete el cambio de modo.
- Iniciar reproducción de video
El seudocódigo que solo admite el cambio fluido es el siguiente:
SurfaceControl.Transaction transaction = new SurfaceControl.Transaction();
transaction.setFrameRate(surfaceControl,
contentFrameRate,
FRAME_RATE_COMPATIBILITY_FIXED_SOURCE,
CHANGE_FRAME_RATE_ONLY_IF_SEAMLESS);
transaction.apply();
beginPlayback();
El seudocódigo que admite el cambio fluido y fluido, como se describió anteriormente, es el siguiente:
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();
}