Frame Rate nelle app mobili — definizione, fps e come migliorare

Autore: IT Sectr Pubblicato: 2026-03-31 Tempo di lettura: 10 min

Il Frame Rate è il numero di fotogrammi che un sistema grafico visualizza al secondo. Nelle applicazioni mobili, la frequenza fotogrammi determina direttamente la fluidità di animazioni, scorrimento e transizioni tra schermate. Secondo Android Developers, 2025, il Frame Rate target è di 60 fps per i display standard e di 120 fps per i dispositivi con alta frequenza di aggiornamento. La deviazione dal valore target porta a balbuzie visive e degrado dell'esperienza utente.

Punti chiave

  • Frame Rate — numero di fotogrammi al secondo (fps) che determina la fluidità dell'interfaccia.
  • Il Frame Rate target standard è 60 fps, corrispondente a 16,6 ms per fotogramma.
  • I dispositivi con display 120 Hz richiedono 120 fps (8,3 ms per fotogramma).
  • I fotogrammi persi causano Jank — balbuzie evidenti nelle animazioni.
  • Il profiling del Frame Rate è il primo passo verso l'ottimizzazione delle prestazioni dell'interfaccia.

Cos'è il Frame Rate

Frame Rate (frequenza fotogrammi) è una metrica misurata in fotogrammi al secondo (fps) che indica quante volte al secondo un'applicazione aggiorna l'immagine sullo schermo. L'occhio umano percepisce il movimento come fluido a partire da 24 fps (cinema), ma un'interfaccia interattiva richiede almeno 60 fps affinché tocchi e animazioni sembrino istantanei. Ogni fotogramma è un ciclo completo: elaborazione dell'input utente, calcolo del Layout, rendering della gerarchia delle viste e output sullo schermo. Se una di queste fasi supera il budget di tempo allocato (16,6 ms a 60 fps), il fotogramma viene saltato e l'utente vede una balbuzie.

È importante distinguere tra il Frame Rate dell'applicazione e la frequenza di aggiornamento del display (Refresh Rate). La frequenza di aggiornamento è una caratteristica hardware dello schermo: quante volte al secondo il display aggiorna fisicamente l'immagine (60, 90, 120 o 144 Hz). Il Frame Rate è quanti fotogrammi al secondo l'applicazione riesce a renderizzare. Se l'applicazione produce 60 fps su un display a 120 Hz, ogni secondo fotogramma verrà duplicato — l'immagine rimane fluida ma non reattiva come potrebbe essere. Secondo Google I/O 2023, i flagship moderni possono mantenere 120 fps in scenari di interfaccia semplici, ma sotto carico pesante (giochi, elenchi complessi) la frequenza scende a 40–60 fps.

Come funziona il rendering dei fotogrammi

Il rendering dei fotogrammi in un'applicazione mobile attraversa una pipeline di diverse fasi. In Android, la pipeline include: elaborazione dell'input (Input), animazione (Animation), misurazione e disposizione (Layout), disegno (Draw), sincronizzazione GPU e output sullo schermo (Swap). Ogni fase viene eseguita su CPU o GPU e il tempo totale di tutte le fasi non deve superare il budget del fotogramma. Per 60 fps il budget è di 16,6 ms, per 120 fps — 8,3 ms. Choreographer (Android) e CADisplayLink (iOS) sincronizzano il rendering con l'intervallo di blanking verticale del display (VSync), garantendo che il fotogramma venga emesso solo al momento dell'aggiornamento dello schermo, evitando il tearing.

In iOS, la pipeline è simile: Run Loop elabora gli eventi, Core Animation calcola i layer, Render Server (un processo separato) renderizza e invia il fotogramma alla GPU. La differenza in iOS è il processo dedicato Render Server, che isola il rendering dall'applicazione principale. Se l'applicazione blocca il thread principale, Render Server può comunque disegnare l'ultimo fotogramma noto, ma le animazioni si fermeranno. Se Render Server stesso non riesce a tenere il passo — la GPU rimane inattiva e il Frame Rate cala. Secondo Apple WWDC 2022, le cause più comuni di basso Frame Rate in iOS sono l'annidamento eccessivo di CALayer, shadowPath pesanti e rendering offscreen.

Tracciamento dei fotogrammi tramite Choreographer

Il codice Kotlin si sottoscrive a Choreographer.FrameCallback e registra il tempo effettivo tra i fotogrammi. Se l'intervallo supera 16,6 ms, viene registrato un fotogramma perso.

kotlin
class FrameRateMonitor {

    private var lastFrameTime = 0L
    private val frameCallback =
        Choreographer.FrameCallback { frameTimeNanos ->
            if (lastFrameTime != 0L) {
                val deltaMs = (frameTimeNanos - lastFrameTime) / 1_000_000f
                if (deltaMs > 16.6f) {
                    Log.w("FrameRate",
                        "Skipped frame: $deltaMs ms")
                }
            }
            lastFrameTime = frameTimeNanos
            Choreographer.getInstance()
                .postFrameCallback(this)
        }

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

Frequenza di aggiornamento del display e Frame Rate

Refresh Rate (frequenza di aggiornamento) è una caratteristica hardware del display che determina quante volte al secondo lo schermo ridisegna fisicamente l'immagine. I display standard hanno 60 Hz, i flagship moderni hanno 90, 120 o 144 Hz. Il Frame Rate dell'applicazione può essere inferiore, uguale o superiore alla frequenza di aggiornamento (in quest'ultimo caso, i fotogrammi in eccesso vengono scartati). Lo scenario ideale è quando il Frame Rate coincide con il Refresh Rate: ogni ciclo hardware riceve un nuovo fotogramma dall'applicazione e il movimento è massimamente fluido. Se il Frame Rate è inferiore, il display ripete l'ultimo fotogramma, percepito come micro-balbuzie.

Android e iOS supportano il cambio dinamico della frequenza di aggiornamento. Android 12+ utilizza Smart Refresh Rate: durante lo scorrimento il sistema aumenta la frequenza a 120 Hz, su contenuti statici la riduce a 60 Hz per risparmiare batteria. iOS ProMotion (iPhone 13 Pro e successivi) funziona in modo simile — la frequenza varia da 10 a 120 Hz a seconda del contenuto. Lo sviluppatore dovrebbe verificare se il dispositivo supporta l'alta frequenza e adattare il budget di tempo per fotogramma. Se l'applicazione non riesce a renderizzare un fotogramma entro 8,3 ms (per 120 Hz), è meglio forzare 60 Hz — questo garantirà un Frame Rate stabile senza fotogrammi persi.

Tipo di displayRefresh RateBudget per fotogrammaDispositivi
Standard60 Hz16,6 msMaggior parte Android/iOS
Alto90 Hz11,1 msOnePlus, Pixel 6+
Flagship120 Hz8,3 msiPhone Pro, Galaxy S22+
Gioco144 Hz6,9 msROG Phone, Nubia RedMagic

Strumenti di misura del Frame Rate

Sia gli strumenti integrati delle piattaforme che i profiler di terze parti sono disponibili per misurare il Frame Rate nelle applicazioni mobili. In Android, lo strumento principale è GPU Profiling (Developer Options → Profile GPU Rendering), che mostra una timeline di ogni fotogramma suddivisa per fasi (Draw, Prepare, Process, Execute). Un'analisi più dettagliata è fornita da Android Studio Profiler — registra un profilo di rendering completo indicando le viste specifiche che causano ridisegni. In iOS, si utilizza Instruments con il modello Core Animation — mostra FPS, tempo di rendering dei layer e il numero di rendering offscreen.

Per il monitoraggio del Frame Rate in produzione, si utilizza Firebase Performance (Android) — raccoglie il Frame Rate in background e lo aggrega per dispositivo, versione del sistema operativo e sessione. In iOS, MetricKit fornisce dati simili tramite MXAnimatoryMetric. Per giochi e applicazioni Flutter, si utilizzano FrameTimingCallback (Flutter) e Unity Profiler. È importante misurare non il Frame Rate medio ma i percentili: P50, P90 e P99. Un'applicazione può mostrare una media di 55 fps ma avere un P99 di 30 fps — ciò significa che l'1% del tempo gli utenti vedono balbuzie gravi, sufficienti per recensioni negative.

Misurazione del Frame Rate in Flutter

L'esempio in Dart mostra come sottoscriversi a FrameTimingCallback in Flutter e registrare il numero di fotogrammi persi. Il callback viene attivato dopo ogni fotogramma completato.

dart
import 'package:flutter/scheduler.dart';

class FrameRateLogger {
    int totalFrames = 0;
    int missedFrames = 0;

    void start() {
        SchedulerBinding.instance
            .addTimingsCallback(_onReportTimings);
    }

    void _onReportTimings(List<FrameTiming> timings) {
        for (final timing in timings) {
            totalFrames++;
            if (timing.totalSpan()
                > Duration(milliseconds: 16)) {
                missedFrames++;
            }
        }
        debugPrint("FPS: \${totalFrames - missedFrames}");
    }
}

Ottimizzazione della frequenza fotogrammi

L'ottimizzazione del Frame Rate inizia con l'identificazione dei colli di bottiglia nella pipeline di rendering. Nella fase di Layout, i problemi principali sono l'annidamento eccessivo della gerarchia delle viste, l'uso di layout relativi (RelativeLayout con molte regole) e le chiamate frequenti a requestLayout. La soluzione è utilizzare ConstraintLayout o una gerarchia piatta, evitando annidamenti superiori a 5–6 livelli. Nella fase di Draw — overdraw: quando un pixel viene disegnato più volte per fotogramma. Ad esempio, uno sfondo di Activity bianco sotto un frammento semitrasparente, sotto il quale c'è un altro livello — ogni pixel viene disegnato tre volte. Lo strumento Debug GPU Overdraw mostra le aree problematiche con indicazione cromatica. Si raccomanda di mantenere l'overdraw a 2x o inferiore.

In iOS, i problemi principali sono cornerRadius e masksToBounds pesanti — causano rendering offscreen, dove Core Animation crea un buffer temporaneo, vi disegna, poi copia il risultato sullo schermo. Il rendering offscreen è facilmente individuabile in Instruments Core Animation: se la riga Renderer è rossa — ci sono problemi. La soluzione è utilizzare UIImageView con immagini precariate invece di cornerRadius, evitare groupOpacity e shouldRasterize se non assolutamente necessario. Per entrambe le piattaforme, è fondamentale minimizzare il numero di chiamate a invalidate() e setNeedsDisplay() — ciascuna di queste chiamate attiva un ciclo completo di ridisegno della vista.

Ottimizzazione della gerarchia in Android

Il codice mostra la sostituzione dell'annidamento profondo di RelativeLayout con una struttura piatta usando ConstraintLayout. Ridurre il livello di annidamento da 4 a 1 riduce il tempo di Layout del 30–50%.

kotlin
// Esempio: struttura piatta tramite ConstraintLayout
class OptimizedView(context: Context) :
    ConstraintLayout(context) {

    private val binding =
        ItemProfileBinding.inflate(
            LayoutInflater.from(context)
        )

    fun bind(user: User) {
        binding.avatar.setImageURI(user.avatarUrl)
        binding.nameText.text = user.name
        // vincolare i dati senza ridisegnare l'intero contenitore
    }
}

Frequenze adattive e Dynamic Frame Rate

Le applicazioni mobili moderne utilizzano sempre più il Frame Rate adattivo — un sistema che regola dinamicamente la frequenza target in base allo scenario corrente. Lo scorrimento veloce richiede 120 fps per fluidità, mentre uno schermo statico necessita solo di 60 fps o addirittura 30 fps per video. In Android, l'adattamento è implementato tramite Choreographer.setFrameInterval (API 33+) e Window.setFrameRate. Lo sviluppatore può specificare una frequenza preferita: setPreferredRefreshRate in SurfaceView o setFrameRate in Window. iOS gestisce automaticamente la frequenza tramite ProMotion, ma lo sviluppatore può impostare esplicitamente preferredFramesPerSecond per CADisplayLink.

Il Dynamic Frame Rate è particolarmente importante per giochi e applicazioni con animazioni. Secondo Google, ridurre il Frame Rate da 120 a 60 Hz su uno schermo statico consente di risparmiare fino al 30–40% di energia GPU. Per raggiungere il miglior equilibrio tra fluidità e consumo energetico, si raccomanda di: misurare il Frame Rate effettivo in diversi scenari, impostare gli fps target in base alla scena (gioco — 60, menu — 30, video — 24) e cambiare modalità tramite componenti Lifecycle-aware in modo che l'applicazione non sprechi risorse renderizzando 120 fps in background quando è minimizzata.

Impostazione del Frame Rate preferito

Il codice Swift imposta preferredFramesPerSecond per CADisplayLink in iOS. Durante lo scorrimento la frequenza sale a 120 Hz, all'arresto scende a 60 Hz.

swift
class AdaptiveFrameRateManager {

    private var displayLink: CADisplayLink?

    func startWithHighRate() {
        displayLink = CADisplayLink(
            target: self,
            selector: #selector(step)
        )
        if #available(iOS 15.0, *) {
            displayLink?.preferredFrameRateRange =
                CAFrameRateRange(
                    minimum: 60,
                    maximum: 120,
                    preferred: 120
                )
        }
        displayLink?.add(to: .current,
            forMode: .common)
    }

    @objc
    private func step() {
        // aggiornamento animazione
    }
}

Domande frequenti

Quale Frame Rate è considerato buono per un'applicazione mobile?

Per le applicazioni mobili, il Frame Rate target è di 60 fps (16,6 ms per fotogramma). Per i dispositivi con display a 120 Hz, sono desiderabili 120 fps. Valori inferiori a 30 fps degradano notevolmente l'esperienza utente.

In cosa differisce il Frame Rate dalla frequenza di aggiornamento del display?

Frame Rate — quanti fotogrammi al secondo renderizza l'applicazione. Refresh Rate — quante volte al secondo il display aggiorna fisicamente l'immagine. Quando il Frame Rate è inferiore al Refresh Rate, il display duplica l'ultimo fotogramma.

Come misurare il Frame Rate in Android?

Utilizza GPU Profiling nelle Opzioni sviluppatore, Android Studio Profiler o Firebase Performance. Per la misurazione programmatica — Choreographer.FrameCallback con calcolo dell'intervallo tra fotogrammi.

Cos'è l'overdraw e come influisce sul Frame Rate?

Overdraw — disegnare lo stesso pixel più volte per fotogramma. Ogni livello extra aumenta il tempo della fase Draw e riduce il Frame Rate. L'overdraw ottimale è 2x, quello critico è 4x e oltre.

Come risparmia batteria il Dynamic Frame Rate?

Su contenuti statici, il Dynamic Frame Rate riduce la frequenza a 30–60 Hz, diminuendo il carico della GPU del 30–40%. Durante lo scorrimento, la frequenza sale a 90–120 Hz per fluidità.

Riepilogo

  • Frame Rate — numero di fotogrammi al secondo che determina la fluidità dell'interfaccia e delle animazioni.
  • Frame Rate target — 60 fps (16,6 ms per fotogramma) per display standard, 120 fps (8,3 ms) per alta frequenza di aggiornamento.
  • I fotogrammi persi causano Jank — balbuzie visibili che degradano l'esperienza utente.
  • Principali cause di basso Frame Rate — annidamento eccessivo delle viste, overdraw e rendering offscreen.
  • Choreographer (Android) e CADisplayLink (iOS) sincronizzano il rendering con VSync.
  • Il Frame Rate adattivo bilancia fluidità e consumo energetico, riducendo il carico della GPU fino al 40%.
  • Il profiling del Frame Rate è il primo passo per ottimizzare le prestazioni di un'applicazione mobile.

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