Jank per applicazioni mobili — cos'è, cause e soluzioni

Autore: IT Sectr Pubblicato: 2026-04-01 Tempo di lettura: 10 min

Jank è un termine che indica scatti evidenti o “balbettii” nell'animazione dell'interfaccia causati dalla perdita di singoli frame. Nelle app mobili, Jank si verifica quando il tempo di rendering del frame supera il budget allocato dalla frequenza di aggiornamento del display. Secondo Android Developers, 2025, Jank è la causa principale della sensazione soggettiva di “lentezza” — un'app può essere funzionalmente perfetta, ma l'utente la percepisce come lenta a causa di FPS instabile.

Punti chiave

  • Jank — frame persi che appaiono come scatti nell'animazione.
  • La causa principale è il superamento del budget di tempo per frame (16,6 ms per 60 FPS).
  • Jank si verifica a causa di Layout pesante, GC lunga, blocco del thread principale o overdraw.
  • Per la diagnosi si usano FrameTimeline (Android) e Instruments (iOS).
  • Eliminare Jank aumenta NPS e fidelizzazione degli utenti del 15–25%.

Cos'è Jank

Jank è un termine della computer grafica che indica un difetto visivo in cui l'animazione si muove a scatti invece di scorrere fluidamente. Nello sviluppo mobile, Jank viene misurato come numero di frame persi (skipped frames) per unità di tempo. Se il sistema non riesce a preparare un frame in tempo per il VSync, il display ripete il frame precedente — si verifica una pausa di 16,6 ms a 60 Hz. Un singolo frame perso può passare inosservato, ma una serie di 3–5 frame persi consecutivi crea una sensazione di “scatto” della durata di 50–80 ms, che l'utente percepisce chiaramente.

Jank è particolarmente critico per le animazioni che devono funzionare a velocità costante: scorrimento dei feed, animazione di apertura dei menu, effetti parallasse, transizioni tra schermate. Secondo uno studio UX di Google (2024), un'app con un tasso di Jank superiore al 3% delle sessioni di scorrimento riceve il 22% di recensioni con una stella in più rispetto a un'app con un tasso inferiore allo 0,5%. Lo strumento Android Vitals traccia automaticamente Jank e lo classifica per gravità: moderato, grave e critico.

Cause principali di Jank

Le cause di Jank si dividono in diverse categorie. La prima è Layout Jank: causata da frequenti chiamate requestLayout() a causa di modifiche alle dimensioni delle View, animazioni LayoutTransition o caricamento dinamico dei contenuti. Ogni chiamata requestLayout attiva Measure + Layout per l'intero sottoalbero delle View, che può richiedere 5–30 ms. La seconda è Draw Jank: correlata all'overdraw e all'uso di drawable pesanti. La terza è Thread Jank: blocco del thread principale a causa di operazioni sincrone — caricamento di file, operazioni sul database nel thread principale, decodifica di Bitmap.

La quarta categoria è GC Jank: garbage collection (GC) in ART/Dalvik o Swift ARC. Quando molti oggetti si accumulano nell'heap, il GC avvia una pausa Stop-The-World di 5–15 ms. Su Android, le pause GC si verificano più spesso durante allocazioni frequenti nei cicli: creazione di oggetti in onDraw(), allocazione negli adapter, espressioni lambda inutilizzate. La quinta è IPC Jank: comunicazione interprocesso (ContentProvider, Binder) sul thread principale. La sesta è Rendering Jank: rendering GPU lento a causa di shader non ottimali o texture di grandi dimensioni.

Tipo di JankCausaDurata tipicaStrumento di rilevamento
LayoutrequestLayout, relayout5–30 msPerfetto, Systrace
DrawOverdraw, drawable pesanti3–20 msGPU Profiling
ThreadBlocco del thread principale10–200 msAndroid Studio Profiler
GCGarbage Collection5–15 msMemory Profiler
RenderingCarico GPU10–50 msGPU Tracer, Xcode GPU

Diagnosi di Jank in Android

In Android, la diagnosi di Jank inizia con la traccia di sistema Perfetto. Perfetto registra l'attività di tutti i thread, CPU, GPU e scheduler. Un indicatore chiaro di Jank sono le righe Choreographer.doFrame e Choreographer.doCallbacks: se l'intervallo tra due chiamate consecutive doFrame supera 16,6 ms, un frame è stato perso. Perfetto mostra la causa esatta — quale chiamata di sistema, lock o GC ha causato il ritardo. In Android Studio Profiler, funzionalità simile è disponibile tramite CPU Profiler.

Per il rilevamento automatico di Jank in produzione, si utilizza FrameMetricsAggregator — un'API che raccoglie statistiche per ogni frame e le aggrega per sessione. In Android 12+ è apparso PerformanceHintManager — un'API per suggerire al sistema la frequenza fotogrammi target. Se l'app indica che funziona in uno scenario a 120 FPS, il sistema può aumentare la frequenza CPU/GPU per prevenire Jank. Per una semplice registrazione di tutti i frame persi, è sufficiente iscriversi a Choreographer.FrameCallback.

Registrazione di Jank tramite Choreographer

Il codice Kotlin si iscrive a Choreographer.FrameCallback e registra ogni frame perso con la durata del ritardo. Il callback viene invocato a ogni VSync.

kotlin
class JankDetector {

    private val frameBudget = 16_666_666L
    private var previousFrameTime = 0L

    private val callback =
        Choreographer.FrameCallback { currentTime ->
            if (previousFrameTime != 0L) {
                val frameDuration =
                    currentTime - previousFrameTime
                val skippedFrames =
                    (frameDuration / frameBudget) - 1
                if (skippedFrames > 0) {
                    Log.w("Jank",
                        "Skipped $skippedFrames frames")
                }
            }
            previousFrameTime = currentTime
            Choreographer.getInstance()
                .postFrameCallback(this)
        }

    fun start() {
        Choreographer.getInstance()
            .postFrameCallback(callback)
    }
}

Diagnosi di Jank in iOS

In iOS, la diagnosi di Jank viene eseguita tramite Instruments con il template Core Animation. Instruments mostra FPS in tempo reale, il numero di rendering fuori schermo e i test di hit. I principali indicatori di Jank in iOS: barre rosse nella timeline Core Animation (superamento del budget del frame), valore alto di Renderer (indica rendering fuori schermo) e FPS basso. Per il monitoraggio in produzione, MetricKit raccoglie report con la metrica MXAnimatoryMetric, che include FPS medio, tempo frame P50 e P95.

La diagnosi nativa di Jank in iOS include CADisplayLink con controllo di timestamp e targetTimestamp. Se il timestamp corrente è significativamente in ritardo rispetto a targetTimestamp, uno o più frame sono stati persi. Apple raccomanda anche di utilizzare os_signpost per la profilazione personalizzata: posizionare un signpost-interval all'inizio e alla fine del rendering del frame e controllare in Instruments quali intervalli superano 16,6 ms. In SwiftUI, per la diagnosi di Jank si usa UIView.invalidateIntrinsicContentSize — le chiamate frequenti a questo metodo indicano un Layout instabile.

CADisplayLink per il rilevamento di Jank

Il codice Swift rileva i frame persi tramite CADisplayLink. Se la differenza tra timestamp e targetTimestamp supera 16,6 ms, Jank viene registrato.

swift
class JankMonitor {

    private var displayLink: CADisplayLink?
    private var totalJank = 0

    func start() {
        displayLink = CADisplayLink(
            target: self,
            selector: #selector(detectJank)
        )
        displayLink?.add(to: .current,
            forMode: .common)
    }

    @objc
    private func detectJank() {
        guard let link = displayLink else { return }
        let delay = link.targetTimestamp
            - link.timestamp
        if delay > 0.0167 {
            totalJank += 1
        }
    }
}

Strumenti di profilazione di Jank

Per la profilazione di Jank, vengono utilizzati sia strumenti integrati nel sistema operativo che SDK di terze parti. Su Android, lo strumento chiave è Perfetto (che ha sostituito Systrace). Perfetto può registrare tracce fino a 30 secondi e analizzarle tramite l'interfaccia web ui.perfetto.dev. Mostra una timeline precisa con l'attività di Choreographer, i thread di rendering (RenderThread) e la GPU. Per l'analisi dettagliata dei problemi GPU, si utilizza AGI (Android GPU Inspector), che mostra non solo il tempo del frame ma anche il carico di specifici blocchi GPU — shader, rasterizzatore, unità texture.

Su iOS, l'equivalente è Instruments con i template Core Animation, Metal System Trace e GPU Driver. Core Animation mostra FPS e tempo frame, Metal System Trace mostra il lavoro GPU fino a ogni draw call. Per la profilazione su dispositivi reali sotto carico, vengono utilizzati Firebase Performance (raccoglie la metrica Screen Rendering) e Sentry(cattura lo stack trace in caso di Jank). La nuova API Android 15 Performance Hint consente allo sviluppatore di indicare al sistema quali frame sono importanti e ricevere avvisi dal sistema quando Jank è imminente.

FrameMetricsAggregator in produzione

Il codice Kotlin utilizza FrameMetricsAggregator per raccogliere statistiche per frame durante una sessione. Dopo aver fermato l'aggregatore, viene visualizzato il numero di frame persi.

kotlin
class JankAggregator(private val activity: Activity) {

    private val aggregator = FrameMetricsAggregator()

    fun startCollection() {
        aggregator.add(activity.window)
    }

    fun stopAndReport() {
        aggregator.remove()
        val result = aggregator.getMetrics()
        val totalFrames = result
            ?.get(FrameMetrics.TOTAL_DURATION)
            ?.size ?: 0
        val jankFrames = result
            ?.get(FrameMetrics.TOTAL_DURATION)
            ?.count { it > 16_666_666L} ?: 0
        Log.d("JankReport",
            "Jank ratio: \${jankFrames * 100 / totalFrames}%")
    }
}

Metodi per eliminare gli scatti dei frame

Eliminare Jank richiede una combinazione di tecniche a seconda del tipo. Per Layout Jank: sostituire le gerarchie profonde con ConstraintLayout/Compose/SwiftUI, utilizzare tag merge, evitare requestLayout nelle animazioni. Per Draw Jank: utilizzare Debug GPU Overdraw per trovare overdraw 4x+, sostituire i drawable pesanti con vettoriali (VectorDrawable/PDF), utilizzare hardware layers con cautela — accelerano il rendering ma consumano più memoria GPU. Per Thread Jank: spostare tutte le operazioni I/O, il lavoro con il database e la decodifica Bitmap su thread in background, utilizzare Kotlin Coroutines con il Dispatcher corretto o RxJava con Schedulers.io().

Per GC Jank: minimizzare le allocazioni in onDraw() e getView(), utilizzare pool di oggetti (ObjectPool), sostituire for-each con for indicizzato, utilizzare data class immutabili in Kotlin con copy() con cautela — copy crea un nuovo oggetto. Per IPC Jank: inizializzare ContentProvider in modo lazy tramite App Startup, spostare le chiamate Binder su un thread in background. Per Rendering Jank: ridurre la dimensione delle texture alla risoluzione massima dello schermo, utilizzare compressione ASTC o ETC2, evitare compilazioni eccessive di shader (compilare gli shader in anticipo). Una soluzione completa è l'esecuzione regolare di profilazione Perfetto/Instruments in CI e il monitoraggio delle regressioni di Jank.

Pattern Anti-Jank: Async Layout

Il codice Kotlin dimostra il caricamento asincrono dei dati sullo schermo dopo reportFullyDrawn, in modo che il lavoro pesante non blocchi il primo frame. Il callback viene invocato dopo che l'utente vede l'interfaccia.

kotlin
class JankSafeLoader {

    suspend fun loadAfterFirstFrame(
        activity: Activity
    ) {
        // garantire che il primo frame sia già stato renderizzato
        if (Build.VERSION.SDK_INT >= 29) {
            activity.reportFullyDrawn()
        }

        // caricamento pesante — dopo il primo frame
        withContext(Dispatchers.IO) {
            val data = fetchHeavyData()
            withContext(Dispatchers.Main) {
                updateUI(data)
            }
        }
    }
}

Domande frequenti

Cos'è Jank nelle app mobili?

Jank sono frame di rendering persi che appaiono come scatti o scossoni evidenti nell'animazione. Si verifica quando il tempo di preparazione del frame supera il budget di tempo (16,6 ms per 60 FPS).

Quali sono le principali cause di Jank?

Layout Jank (requestLayout frequente), Draw Jank (overdraw), Thread Jank (blocco del thread principale), GC Jank (garbage collection), IPC Jank (chiamate Binder) e Rendering Jank (shader pesanti).

Come diagnosticare Jank in Android?

Utilizzare Perfetto per il tracing di sistema, GPU Profiling per l'analisi delle fasi del frame e FrameMetricsAggregator per il monitoraggio in produzione. In Android Studio — CPU Profiler con Deep Java Trace.

Come misurare Jank in iOS?

Tramite Instruments con template Core Animation o Metal System Trace. Per la produzione — MetricKit con MXAnimatoryMetric. Programmaticamente — CADisplayLink controllando la differenza tra timestamp e targetTimestamp.

Quale percentuale di Jank è considerata critica?

Secondo Google, un tasso di Jank superiore al 3% delle sessioni di scorrimento (3 scorrimenti su 100 contengono uno scatto) porta a un aumento del 22% delle recensioni negative. Il tasso obiettivo è inferiore allo 0,5% delle sessioni di scorrimento.

Riepilogo

  • Jank — frame persi che causano scatti visibili nell'animazione delle app mobili.
  • Cause principali: Layout Jank, Draw Jank, Thread Jank, GC Jank, IPC Jank e Rendering Jank.
  • Diagnosi di Jank su Android — tramite Perfetto, GPU Profiling e FrameMetricsAggregator.
  • Diagnosi di Jank su iOS — tramite Instruments, CADisplayLink e MetricKit.
  • Eliminare Jank richiede una combinazione di: gerarchie piatte, thread in background, allocazioni minimizzate, caching.
  • Tasso di Jank obiettivo — meno dello 0,5% delle sessioni di scorrimento con scatti.
  • La profilazione regolare in CI previene le regressioni di prestazioni prima che raggiungano la produzione.

Svilupperemo un'applicazione mobile chiavi in mano

IT Sectr crea applicazioni iOS e Android per startup e aziende dal 2017. Ti consulteremo e ti proporremo la soluzione migliore.

Discuti il progetto

Leggi anche