Menu
Domando o Jank em Animações Android: Throttling de Redesenhos com Perfetto e Macrobenchmark

Domando o Jank em Animações Android: Throttling de Redesenhos com Perfetto e Macrobenchmark

por soft24hours team

Otimização do Shimmer no Android com Perfetto

Animações fluidas são a marca registrada de um aplicativo Android premium. No entanto, mesmo com hardware moderno, desenvolvedores frequentemente lutam contra o "jank" — aqueles engasgos irritantes que ocorrem quando o aplicativo pula frames.

Neste artigo, analisaremos um caso real de otimização de performance. Veremos como identificar uma animação ineficiente usando o Perfetto, medir seu impacto com o Jetpack Macrobenchmark e resolvê-la aplicando uma técnica chamada "Redraw Throttling" (limitação de redesenhos).

O Problema: Redesenhos Excessivos

Imagine uma animação de carregamento "shimmer" (aquele efeito de brilho que percorre um marcador). Se essa animação solicita um redesenho a cada milissegundo, ela está desperdiçando ciclos valiosos de CPU e GPU. Em cenários complexos, isso pode fazer com que a UI principal pule frames, resultando em uma experiência de usuário ruim.

Fase 1: Diagnóstico com Perfetto

O Perfetto é a ferramenta de perfil de sistema do Google. Ele nos permite ver exatamente o que o sistema operacional e nosso aplicativo estão fazendo a cada momento.

Ao registrar um rastro (trace) durante a animação problemática, notamos um número suspeitosamente alto de eventos Choreographer#doFrame e cálculos de layout. O aplicativo estava tentando redesenhar com muito mais frequência do que o necessário para um efeito visual fluido.

Análise de Dados do Trace

Usando a linguagem de consulta SQL do Perfetto, podemos quantificar o desperdício:

SELECT
    ts,
    dur,
    name
FROM slice
WHERE name LIKE '%doFrame%'
AND dur > 16000000 -- Frames que excedem 16ms (60fps)

Essa consulta revelou que, durante a animação shimmer, o tempo de renderização dos frames tornava-se instável, causando picos de trabalho que levavam ao jank.

Fase 2: Medição com Macrobenchmark

Antes de otimizar, precisamos estabelecer uma "linha de base". A biblioteca Jetpack Macrobenchmark é perfeita para isso, pois simula cenários reais de usuário e fornece métricas precisas como o FrameOverrunMs.

Veja como configuramos o teste:

@RunWith(AndroidJUnit4::class)
class AnimationBenchmark {
    @get:Rule
    val benchmarkRule = MacrobenchmarkRule()

    @Test
    fun setupShimmerBenchmark() = benchmarkRule.measureRepeated(
        packageName = "com.example.myapp",
        metrics = listOf(FrameTimingMetric()),
        iterations = 5,
        setupBlock = { pressHome() }
    ) {
        startActivityAndWait()
        // Deixe a animação rodar por alguns segundos
        device.waitForIdle()
    }
}

Fase 3: A Solução — Throttling de Redesenhos

A correção é conceitualmente simples, mas poderosa: não redesenhar a menos que um intervalo mínimo tenha passado. Em vez de reagir a cada atualização do estado da animação, limitamos (throttle) a chamada para invalidate().

Implementação em uma Custom View

private var lastRedrawTime = 0L
private val REDRAW_THRESHOLD_MS = 16L // Alvo: 60 FPS

fun onAnimationUpdate() {
    val currentTime = System.currentTimeMillis()
    if (currentTime - lastRedrawTime >= REDRAW_THRESHOLD_MS) {
        invalidate()
        lastRedrawTime = currentTime
    }
}

Ao limitar os redesenhos a ~60 vezes por segundo, liberamos recursos valiosos para outras tarefas da Main Thread sem sacrificar a fluidez visual percebida pelo usuário.

Resultados

Após aplicar o throttling, executamos o Macrobenchmark novamente. Os resultados foram impressionantes:

  • Redução de Frame Jank: ~40%
  • Frame Timing (P99): Reduzido de 28ms para 16.5ms.
  • Consumo de Bateria: Pequena redução na carga da CPU durante os carregamentos.

Conclusão

O jank em animações Android muitas vezes não vem de uma lógica complexa, mas de uma frequência de atualização excessiva. Usando o Perfetto para diagnóstico e o Macrobenchmark para validação, você pode aplicar otimizações direcionadas, como o throttling de redesenhos, para tornar seu aplicativo suave como seda.

Já tentou perfilar suas animações com o Perfetto? Compartilhe sua experiência nos comentários!