Quando uma animação é iniciada no Android, a tela geralmente aumenta para a taxa de atualização máxima para garantir uma experiência suave. Para animações pequenas, como barras de progresso e visualizadores de áudio, essa alta taxa de atualização é desnecessária e resulta em alto consumo de energia.
A partir do Android 15, com o recurso de taxa de atualização adaptativa (ARR, na sigla em inglês), os dispositivos ativados podem reduzir a permanência de alta taxa de atualização em duas frentes:
- Com as novas otimizações de gerenciamento de frame rate da plataforma, os apps podem renderizar com um frame rate mais baixo por padrão e só aumentar para um frame rate alto quando necessário.
- A taxa de atualização da tela corresponde dinamicamente à taxa de renderização de conteúdo sem problemas.
Embora a maioria dos apps se beneficie da ARR sem modificações, você também pode substituir o comportamento padrão da taxa de frames conforme necessário.
Esta página descreve o seguinte:
- Como a taxa de frames de cada visualização é determinada.
- A política geral de como o ARR determina a taxa de frames.
- Como substituir manualmente o comportamento padrão da taxa de frames.
O mecanismo de votação de visualizações
No sistema de visualização do Android, cada visualização na hierarquia da interface pode expressar a taxa de frames preferida. Essas preferências são coletadas e combinadas para determinar uma taxa de frames final para cada frame. Isso é feito por um mecanismo de votação em que cada visualização vota com base no atributo de taxa de frames, que pode ser uma categoria ou uma taxa específica. As visualizações geralmente votam quando são desenhadas ou atualizadas. Esses votos são combinados para determinar uma taxa de frames final, que é enviada à camada de nível mais baixo como uma dica para renderização.
No momento, a maioria das visualizações usa uma taxa de atualização "Normal", geralmente definida como 60 Hz. Para taxas de atualização mais altas, use APIs específicas para personalizar as preferências. O sistema geralmente seleciona a taxa de atualização mais alta. Para mais informações sobre como usar essas APIs, consulte a seção Definir a taxa de frames ou a categoria. As políticas gerais sobre taxas de frames são descritas na seção Política geral de ARR.
Categorias de frame rate
Na classe View
, há diferentes categorias de taxa de frames que podem ser usadas na votação. Confira a descrição de cada categoria:
REQUESTED_FRAME_RATE_CATEGORY_DEFAULT
: esse valor pode ser definido para retornar ao comportamento padrão, indicando que esta visualização não tem dados para a taxa de frames.REQUESTED_FRAME_RATE_CATEGORY_NO_PREFERENCE
: a visualização não vai influenciar explicitamente a taxa de frames. Isso significa que, mesmo que a visualização esteja ativa, o framework não a considerará ao determinar a taxa de frames.REQUESTED_FRAME_RATE_CATEGORY_NORMAL
: indica uma frame rate intermediária adequada para animações que não exigem taxas mais altas ou não se beneficiam de alta fluidez. Normalmente, é 60 Hz ou próximo disso.REQUESTED_FRAME_RATE_CATEGORY_HIGH
: indica uma taxa de frames adequada para animações que exigem uma taxa alta, o que pode aumentar a fluidez, mas também o uso de energia.
Uma visualização só vota se precisar ser redesenhada. A taxa de frames final é determinada pelo voto mais alto. Por exemplo, se todos os votos forem para "Normal", essa opção será selecionada. Quando os votos "Normal" e "Alto" ocorrem, "Alto" é escolhido.
Frame rate
Além das categorias de taxa de frames, uma visualização também pode especificar uma taxa de frames preferida, como 30, 60 ou 120 Hz. Quando vários votos de taxa de frames são dados, a taxa final é determinada pelas seguintes regras:
- Múltiplos entre si: se as taxas de frames votadas forem múltiplas entre si, o valor mais alto será escolhido. Por exemplo, se houver dois votos (30 Hz e 90 Hz), 90 Hz será selecionado como a taxa de frames final.
- Não são múltiplos um do outro:
- Se algum dos votos for maior que 60 Hz, ele será considerado "Alto".
- Se todos os votos forem de 60 Hz ou menos, ele será considerado um voto "Normal".
Além disso, se houver uma combinação de valores e categorias de frame rate, o valor mais alto geralmente determina a taxa de renderização final. Por exemplo, com uma combinação de uma opção de 60 Hz e uma "Alta", ou uma opção de 120 Hz e uma "Normal", a taxa de renderização normalmente seria definida como 120 Hz.
Além dos votos de um app, também pode haver outras dicas enviadas à camada de nível mais baixo de diferentes componentes no mesmo frame. Muitos deles podem ter origem em componentes da interface do sistema, como a tela de notificações, a barra de status, a barra de navegação e outros. Os valores finais de taxa de frames são determinados com base nos votos de vários componentes.
Definir a taxa de frames ou a categoria
Em determinadas circunstâncias, você pode ter uma taxa de frames preferida para uma visualização. Por exemplo, você pode definir a taxa de frames preferida como "Alta" para uma visualização e aumentar a taxa de frames se uma animação parecer instável. Além disso, se houver uma animação lenta ou estática sobre um vídeo (geralmente reproduzido a 24 ou 30 Hz), talvez seja melhor executar a animação a uma taxa menor que "Normal" para reduzir o consumo de energia.
Você pode usar as APIs setRequestedFrameRate()
e
getRequestedFrameRate()
para designar a taxa de frames ou
categoria preferida de uma determinada visualização.
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);
Para exemplos de uso, consulte TextureView
.
Política geral de ARR
Na seção anterior, discutimos que a maioria das animações é mostrada a 60 Hz por padrão, já que cada visualização tem "Normal" definido como a taxa de frames preferida. No entanto, há exceções em que o frame rate é aumentado para "Alto" para garantir animações mais suaves.
A política geral de ARR é a seguinte:
- Aumento de toque: quando um evento de toque (
MotionEvent.ACTION_DOWN
) é detectado, a taxa de atualização é aumentada para "Alta" por algum tempo após o toque ser liberado para manter a capacidade de resposta. - Gestos de deslizar: são processados de maneira diferente. A taxa de atualização diminui gradualmente à medida que a velocidade do deslize diminui. Confira mais detalhes sobre esse comportamento na seção Melhoria na rolagem.
- Inicialização de apps e transições de janela: a taxa de atualização também é aumentada por algum tempo durante a inicialização de apps, a inicialização de janelas e as transições de janelas para garantir uma experiência visual suave.
- Animações: animações que envolvem movimento ou mudanças de tamanho recebem automaticamente uma taxa de atualização mais alta para aumentar a suavidade quando a posição ou o tamanho de uma visualização muda.
SurfaceView
eTextureView
: os frame rates definidos explicitamente paraTextureView
eSurfaceView
são respeitados e aplicados de acordo.
Ativar e desativar o aumento de toque
É possível ativar e/ou desativar o aumento de toque no nível Window
. Por padrão, quando um usuário toca e tira o dedo da tela, a taxa de renderização aumenta por algum tempo. As APIs setFrameRateBoostOnTouchEnabled()
e getFrameRateBoostOnTouchEnabled()
permitem evitar o aumento da taxa de renderização quando um Window
específico é tocado.
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()
Melhoria na rolagem
Um caso de uso importante para otimizar a taxa de frames de forma dinâmica é melhorar a experiência de rolagem (movimento rápido). Muitos aplicativos dependem muito do gesto de deslizar para cima para ver conteúdo novo. A melhoria da rolagem do ARR ajusta dinamicamente a taxa de atualização à medida que o gesto de deslizar diminui a velocidade, reduzindo gradualmente a taxa de frames. Isso oferece uma renderização mais eficiente, mantendo a rolagem suave.
Essa melhoria se aplica especificamente a componentes de IU roláveis, incluindo
ScrollView
, ListView
e GridView
, e pode não estar
disponível para todas as implementações personalizadas.
O recurso de rolagem de ARR está disponível para RecyclerView
e
NestedScrollView
. Para ativar esse recurso no seu app, faça upgrade para as versões mais recentes de AndroidX.recyclerview
e AndroidX.core
. Consulte a tabela a seguir para mais detalhes.
Biblioteca |
Versão |
|
1.4.0 |
|
1.15.0 |
Definir as informações de velocidade
Se você tiver um componente rolável personalizado e quiser aproveitar o recurso de
rolagem, chame setFrameContentVelocity()
em todos os frames durante a
rolagem suave ou o deslizamento rápido. Confira este exemplo de snippet de código:
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()
Para mais exemplos, consulte RecyclerView
e
ScrollView
. Para definir a velocidade corretamente, calcule a velocidade do conteúdo (pixels por segundo) manualmente se as informações necessárias não puderem ser obtidas de Scroller
ou OverScroller
.
Se setFrameContentVelocity()
e getFrameContentVelocity()
forem chamados em Views que não são componentes roláveis, eles não terão efeito, já que o movimento aciona automaticamente uma taxa de frames aumentada com base na política atual.
As informações de velocidade são essenciais para ajustar a taxa de renderização. Por exemplo, considere o gesto de deslizar. No início, a velocidade de um movimento rápido pode ser alta, exigindo uma taxa de renderização maior para garantir a suavidade. À medida que o gesto avança, a velocidade diminui, permitindo que a taxa de renderização seja reduzida.
Ativar e desativar o ARR
O ARR é ativado por padrão para aumentar a eficiência energética. Embora seja possível desativar esse recurso, não é recomendável, já que o app consumiria mais energia. Só desative esse recurso se encontrar problemas que afetem significativamente a experiência do usuário.
Para ativar ou desativar o ARR, use a API
setFrameRatePowerSavingsBalanced()
em um Window
ou a API
isFrameRatePowerSavingsBalanced()
no arquivo styles.xml
.
O snippet a seguir mostra como ativar ou desativar o ARR em um Window
:
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()
Para desativar o ARR pelo arquivo styles.xml
, adicione o
seguinte item ao seu estilo em res/values/styles.xml
:
<style name="frameRatePowerSavingsBalancedDisabled">
<item name="android:windowIsFrameRatePowerSavingsBalanced">false</item>
</style>
ARR para o Compose
O Compose 1.9 também adiciona suporte à taxa de atualização adaptativa.
No sistema de visualização, use o método setRequestedFrameRate()
para
solicitar uma taxa de frames específica para uma visualização. No Compose, um novo modificador permite especificar a taxa de frames de um elemento combinável. Esse modificador funciona
de maneira semelhante a setRequestedFrameRate()
, aceitando um valor de taxa de frames
positivo (em Hz) ou uma categoria de taxa de frames predefinida,
FrameRateCategory
.
As assinaturas das APIs são as seguintes:
Modifier.preferredFrameRate(frameRate: Float)
Modifier.preferredFrameRate(frameRateCategory: FrameRateCategory)
No snippet abaixo, o novo modificador de taxa de frames (Modifier.requestedFrameRate(120f))
é aplicado a um elemento combinável Text
. Esse modificador faz com que o elemento combinável Text
solicite uma taxa de frames preferida de 120 ao ser desenhado ou animado (por exemplo, com mudanças de opacidade):
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
)
}
As taxas de frames preferidas de todos os elementos combináveis são coletadas e
consolidadas para determinar a taxa de frames final de cada frame. Para mais detalhes, consulte SetFrameRateSample
e SetFrameRateCategorySample
.