Menu
Domare lo Jank nelle Animazioni Android: Throttling dei Ridisegni con Perfetto e Macrobenchmark

Domare lo Jank nelle Animazioni Android: Throttling dei Ridisegni con Perfetto e Macrobenchmark

di soft24hours team

Ottimizzazione dello Shimmer in Android con Perfetto

Le animazioni fluide sono il segno distintivo di un'app Android premium. Eppure, anche con l'hardware moderno, gli sviluppatori spesso combattono contro lo "jank" — quei fastidiosi micro-scatti che si verificano quando l'app salta dei frame.

In questo articolo, analizzeremo un caso reale di ottimizzazione delle prestazioni. Vedremo come identificare un'animazione inefficiente utilizzando Perfetto, misurarne l'impatto con Jetpack Macrobenchmark e risolverla applicando una tecnica chiamata "Redraw Throttling" (limitazione dei ridisegni).

Il Problema: Ridisegni Eccessivi

Immagina un'animazione di caricamento "shimmer" (quell'effetto di luce che scorre su un segnaposto). Se questa animazione richiede un ridisegno ad ogni singolo millisecondo, sta sprecando cicli di CPU e GPU preziosi. In scenari complessi, questo può causare il salto di frame della UI principale, portando a un'esperienza utente scadente.

Fase 1: Diagnosi con Perfetto

Perfetto è lo strumento di profilazione a livello di sistema di Google. Ci permette di vedere esattamente cosa sta facendo il sistema operativo e la nostra app in ogni momento.

Registrando una traccia durante l'animazione incriminata, abbiamo notato un numero sospettatamente alto di eventi Choreographer#doFrame e calcoli di layout. L'app stava tentando di ridisegnare molto più spesso di quanto necessario per un effetto visivo fluido.

Analisi dei Dati della Traccia

Utilizzando il linguaggio di query SQL di Perfetto, possiamo quantificare lo spreco:

SELECT
    ts,
    dur,
    name
FROM slice
WHERE name LIKE '%doFrame%'
AND dur > 16000000 -- Frame che superano i 16ms (60fps)

Questa query ha rivelato che durante l'animazione shimmer, il tempo di rendering dei frame diventava instabile, causando picchi di lavoro che portavano allo jank.

Fase 2: Misurazione con Macrobenchmark

Prima di ottimizzare, dobbiamo stabilire una "baseline" (punto di riferimento). La libreria Jetpack Macrobenchmark è perfetta per questo, poiché simula scenari utente reali e fornisce metriche precise come il FrameOverrunMs.

Ecco come abbiamo impostato il test:

@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()
        // Lascia correre l'animazione per alcuni secondi
        device.waitForIdle()
    }
}

Fase 3: La Soluzione — Throttling dei Ridisegni

Il fix è concettualmente semplice ma potente: non ridisegnare a meno che non sia passato un intervallo minimo. Invece di reagire ad ogni aggiornamento dello stato dell'animazione, limitiamo (throttle) la chiamata a invalidate().

Implementazione in una Custom View

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

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

Limitando i ridisegni a ~60 volte al secondo, liberiamo risorse preziose per altre attività del Main Thread senza sacrificare la fluidità visiva percepita dall'utente.

Risultati

Dopo aver applicato il throttling, abbiamo eseguito nuovamente il Macrobenchmark. I risultati sono stati impressionanti:

  • Riduzione del Frame Jank: ~40%
  • Frame Timing (P99): Ridotto da 28ms a 16.5ms.
  • Consumo Batteria: Leggera riduzione del carico CPU durante i caricamenti.

Conclusione

Lo jank nelle animazioni Android spesso non deriva da una logica complessa, ma da una frequenza di aggiornamento eccessiva. Utilizzando Perfetto per la diagnosi e Macrobenchmark per la validazione, puoi applicare ottimizzazioni mirate come il throttling dei ridisegni per rendere la tua app setosa al tatto.

Hai già provato a profilare le tue animazioni con Perfetto? Condividi la tua esperienza nei commenti!