FPS dans les applications mobiles : essence, calcul et optimisation

Auteur : IT Sectr Publié le : 2026-04-01 Temps de lecture : 11 min

Le FPS (Frames Per Second) est une métrique qui indique le nombre d'images individuelles qu'un système graphique restitue en une seconde. Dans le développement mobile, le FPS est un indicateur standard des performances de l'interface utilisateur : plus le FPS est élevé, plus les animations sont fluides et plus l'interface est réactive. Selon Google Android Performance, 2025, la valeur cible de FPS pour les applications mobiles est de 60 images par seconde — le seuil à partir duquel l'œil humain perçoit le mouvement comme continu et fluide.

Points clés

  • FPS — nombre d'images par seconde, la métrique principale de fluidité de l'interface utilisateur.
  • Valeur cible — 60 FPS, temps par image — 16,6 ms.
  • Pour les écrans à haute fréquence de rafraîchissement, 120 FPS sont requis (8,3 ms par image).
  • Une chute du FPS en dessous de 30 est perceptible à l'œil nu sous forme de saccades et de latences.
  • La surveillance du FPS en production aide à identifier les régressions de performances.

Qu'est-ce que le FPS

FPS (Frames Per Second) est une unité de mesure de la fréquence d'images utilisée en infographie, en vidéo et dans les interfaces mobiles. Chaque image est une image statique affichée à l'écran pendant une courte période. Avec des changements rapides d'images, le cerveau les perçoit comme un mouvement continu — cet effet s'appelle la persistance de la vision. Pour les applications mobiles, le FPS est une métrique critique car toute image perdue transforme une animation fluide en une saccade perceptible. L'application doit restituer chaque image strictement dans le budget de temps : 16,6 ms pour 60 FPS, 11,1 ms pour 90 FPS, 8,3 ms pour 120 FPS.

Le FPS est mesuré non seulement pour l'interface utilisateur, mais aussi pour les jeux, la vidéo et la caméra. Dans les jeux, le FPS dépend de la complexité de la scène, de la qualité des textures et de la puissance du GPU. Dans la vidéo, le FPS est fixe (24, 30, 60 ips) et déterminé par le contenu. Dans les applications mobiles, le FPS dépend de l'efficacité du code de l'interface utilisateur : complexité de la mise en page, nombre de vues, fréquence de redessinage et travail du GC (Garbage Collection). Selon l'Apple WWDC 2022, le FPS moyen d'une application peut chuter de 10 à 15 % en raison de mises à jour inefficaces des collections (reloadData au lieu d'insert/delete/dequeueReusableCell). La mesure du FPS en temps réel est une pratique courante pour les ingénieurs QA et les développeurs travaillant sur les performances.

Comment le FPS est calculé

Le calcul du FPS dans une application mobile est basé sur la mesure du temps entre des images consécutives. La formule la plus simple : FPS = 1000 / deltaTimeMs, où deltaTimeMs est l'intervalle entre la fin de l'image précédente et la fin de l'image actuelle. Si l'image actuelle a été rendue en 20 ms, FPS = 1000 / 20 = 50. Cependant, en pratique, le FPS est rarement stable, même en une seconde : un profil typique comprend des images de 12 à 16 ms entrecoupées d'images sautées (jank) ou lentes (40 à 60 ms). Par conséquent, le FPS est mesuré comme une moyenne mobile sur 1 à 5 secondes ou comme des percentiles de la distribution du temps d'image.

Sur Android, le FPS est calculé via Choreographer, qui reçoit un rappel de VSync (impulsion de synchronisation de l'écran). Chaque rappel correspond à une image. Si le rappel n'arrive pas, l'image est sautée. Choreographer permet de mesurer le nombre exact d'images par seconde et le nombre d'images sautées. Sur iOS, CADisplayLink fonctionne de manière similaire — il est appelé chaque fois que l'écran est prêt à restituer une nouvelle image. La propriété timestamp contient l'heure exacte de la dernière image, et targetTimestamp l'heure prévue de la suivante. La différence entre eux est le budget de temps pour l'image actuelle.

Surveillance du FPS via CADisplayLink

Le code Swift démontre une surveillance simple du FPS via CADisplayLink. Le compteur frameCount s'incrémente à chaque appel, et une fois par seconde, le FPS réel est calculé.

swift
class FpsCounter {

    private var displayLink: CADisplayLink?
    private var frameCount = 0
    private var lastTime = TimeInterval(0)

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

    @objc
    private func countFrame() {
        frameCount += 1
        let now = Date().timeIntervalSince1970

        if now - lastTime >= 1.0 {
            print("FPS: \(frameCount)")
            frameCount = 0
            lastTime = now
        }
    }
}

Pourquoi 60 FPS est la norme

La norme 60 FPS (ou 60 Hz) s'est imposée dans l'industrie pour plusieurs raisons. La première est physiologique : l'œil humain ne distingue pas les images individuelles à des fréquences supérieures à 50–60 Hz, les percevant comme un mouvement fluide. Ce seuil est appelé Critical Flicker Fusion (CFF). La deuxième est historique : les premiers tubes cathodiques (CRT) fonctionnaient à 60 Hz aux États-Unis (NTSC) et à 50 Hz en Europe (PAL). Les écrans LCD modernes ont hérité de cette fréquence. La troisième est technique : pour les animations de l'interface utilisateur, 60 FPS offre une latence de réponse tactile inférieure à la milliseconde, ce qui est essentiel pour la saisie de texte, le défilement et le glissement.

Pour les développeurs mobiles, 60 FPS n'est pas seulement une recommandation, mais un budget strict de 16,6 ms par image. Ce budget est réparti entre toutes les phases de rendu : Entrée (1–2 ms), Animation (2–3 ms), Mise en page (3–5 ms), Dessin (3–5 ms) et Échange (1–2 ms). Si une phase dépasse son sous-budget, l'image peut ne pas tenir dans 16,6 ms. Google Android Performance recommande de rester entre 12 et 14 ms pour la préparation de l'image, en laissant 2 à 4 ms de marge pour les interruptions système (GC, threads en arrière-plan). Selon Firebase Performance, les applications avec un FPS moyen inférieur à 52 et un P99 FPS inférieur à 30 reçoivent 35 % de plaintes de performances en plus dans les avis Google Play.

FPS et temps d'image : relation

FPS et temps d'image sont les deux faces d'une même métrique, et il est important de ne pas les confondre. Le FPS est la vitesse, le temps d'image est la latence. À 60 FPS, chaque image prend 16,6 ms. À 30 FPS — 33,3 ms. Mais le FPS est une métrique non linéaire : une chute de 60 à 30 FPS signifie que le temps d'image a doublé, tandis qu'une chute de 30 à 20 signifie une augmentation de 1,5 fois. Par conséquent, les profileurs affichent le temps d'image plutôt que le FPS — cela permet de voir les images problématiques au lieu d'une fréquence moyenne. Par exemple, une moyenne de 55 FPS peut cacher le fait que 5 % des images ont un temps d'image de 50 à 100 ms — ces images provoquent des saccades (Jank) mais n'affectent pas significativement le FPS moyen.

Lors de l'analyse des performances, il est recommandé de regarder non pas le FPS moyen, mais l'histogramme du temps d'image. Dans Android Studio Profiler et iOS Instruments, le temps d'image est affiché sous forme d'échelle où la zone verte va jusqu'à 16,6 ms (60 FPS), la zone jaune de 16,6 à 33,3 ms (30–60 FPS) et la zone rouge au-delà de 33,3 ms (moins de 30 FPS). Chaque colonne rouge est un ralentissement perceptible par l'utilisateur. Une règle pratique : P95 Frame Time (95 % des images tiennent dans X ms) est une métrique plus fiable que le FPS moyen. Si le P95 Frame Time dépasse 32 ms (30 FPS), l'application est perçue comme lente même avec un FPS moyen de 50.

Conversion du temps d'image en FPS

Une fonction Kotlin pour convertir un tableau de temps d'image en FPS avec des percentiles. Elle retourne non seulement le FPS moyen, mais aussi P50, P90 et P99 pour une analyse détaillée.

kotlin
data class FpsReport(
    val average: Float,
    val p50: Float,
    val p90: Float,
    val p99: Float
)

fun List<Long>.toFpsReport(): FpsReport {
    val fpsValues = this.map { ms ->
        if (ms > 0) 1000f / ms else 0f
    }.sorted()

    return FpsReport(
        average = fpsValues.average().toFloat(),
        p50 = fpsValues[fpsValues.size / 2],
        p90 = fpsValues[(fpsValues.size * 90 / 100)],
        p99 = fpsValues[(fpsValues.size * 99 / 100)]
    )
}

FPS élevé et nouveaux écrans

Les appareils mobiles modernes avec des écrans à 90, 120 et 144 Hz imposent de nouvelles exigences au FPS. Si une application délivre 60 FPS sur un écran 120 Hz, l'utilisateur voit des micro-saccades car un cycle de rafraîchissement sur deux reçoit la même image. Pour maintenir 120 FPS, le budget par image passe de 16,6 à 8,3 ms — ce qui nécessite un code de rendu deux fois plus efficace. Selon les développeurs Android (Google I/O 2023), pour atteindre 120 FPS stables, il est nécessaire d'éviter les allocations dans le cycle de dessin, de minimiser le nombre de vues dans la hiérarchie (moins de 80), d'abandonner les drawables lourds au profit de VectorDrawable et d'utiliser surfaceView pour les graphiques complexes.

La situation est similaire sur iOS : l'iPhone Pro avec ProMotion (120 Hz) nécessite deux fois plus d'images, mais le temps par image est réduit de moitié. Apple note que toutes les animations n'ont pas besoin de fonctionner à 120 FPS — Core Animation réduit automatiquement la fréquence d'images pour les éléments statiques ou à évolution lente. Cependant, le défilement, les animations gestuelles et les transitions doivent fournir 120 FPS pour une sensation « soyeuse ». Les principaux problèmes lors du passage de 60 à 120 FPS : augmentation de la consommation d'énergie (25–40 % pour le GPU), échauffement de l'appareil et throttling — lorsque la fréquence d'images chute à cause de la surchauffe. Il est recommandé d'implémenter un mécanisme de secours : si le temps d'image dépasse constamment 8,3 ms, réduire programmatiquement la fréquence d'images cible à 60 FPS plutôt que d'attendre le throttling système.

Commutateur 60/120 FPS

Le code Java pour Android détermine si l'appareil peut prendre en charge 120 FPS et bascule le mode de rendu. Display.getMode est utilisé pour déterminer les fréquences de rafraîchissement prises en charge.

java
class FpsModeSwitcher {

    static boolean canDo120Fps(Activity activity) {
        Display display = activity.getWindowManager()
            .getDefaultDisplay();
        for (Display.Mode mode : display.getSupportedModes()) {
            if (mode.getRefreshRate() >= 120f) {
                return true;
            }
        }
        return false;
    }
}

Optimisation du FPS dans les applications

L'optimisation du FPS nécessite une approche systématique, commençant par le profilage et se terminant par le refactoring des zones problématiques. La première étape consiste à mesurer le FPS actuel avec un profileur. La deuxième étape consiste à trouver les images qui dépassent le budget. Sur Android, cela peut être fait via GPU Profiling ou Perfetto. Sur iOS — Instruments avec le modèle Core Animation. La troisième étape consiste à éliminer les causes : réduire le overdraw, diminuer la profondeur de la hiérarchie des vues, remplacer la phase de mise en page par ConstraintLayout, ajouter le ViewHolder Recycling et déplacer les calculs lourds vers un thread d'arrière-plan.

Les optimisations spécifiques au FPS incluent : Frame Pacing — un mécanisme qui répartit uniformément le temps entre les images pour éviter les « rafales » d'images rapides et lentes. Sur Android, Choreographer.FrameCallback avec un intervalle fixe permet d'implémenter le Frame Pacing. Sur iOS, CADisplayLink.preferredFrameRateRange fait de même. La deuxième méthode — Triple Buffering : le système utilise trois tampons au lieu de deux, permettant au GPU de commencer à rendre l'image suivante sans attendre la libération de la précédente. Android active automatiquement le Triple Buffering si nécessaire, mais sur iOS, le développeur peut le demander explicitement via CAMetalLayer. La troisième — Texture Caching : mise en cache des bitmaps dans la mémoire GPU pour éviter de les recharger à chaque image.

Frame Pacing via Choreographer

Un exemple Kotlin démontre l'implémentation du Frame Pacing avec un intervalle fixe de 16,6 ms. Tous les rappels arrivent à un intervalle uniforme, même si le système est en retard.

kotlin
class PacedFrameRenderer {

    private val targetDelta = 16_666_666L // 16.6 ms (60 FPS)
    private var lastFrameTime = 0L

    private val frameCallback =
        Choreographer.FrameCallback { frameTimeNanos ->
            val delta = frameTimeNanos - lastFrameTime
            if (delta >= targetDelta) {
                onFrame(delta)
                lastFrameTime = frameTimeNanos
            }
            Choreographer.getInstance()
                .postFrameCallback(this)
        }

    private fun onFrame(delta: Long) {
        // rendu d'image
    }
}

Foire aux questions

Quel FPS est considéré comme confortable pour l'utilisateur ?

60 FPS est un niveau confortable pour les applications mobiles. La différence entre 60 et 120 FPS n'est perceptible que sur les écrans à haute fréquence de rafraîchissement lors d'animations rapides (défilement, glissement). En dessous de 30 FPS — inconfort.

Comment le FPS est-il lié au temps d'image ?

FPS = 1000 / FrameTime (ms). Si le temps d'image = 16,6 ms, FPS = 60. Si le temps d'image = 33,3 ms, FPS = 30. Il est recommandé de surveiller le temps d'image plutôt que le FPS, car il montre les images problématiques.

Pourquoi le FPS chute-t-il lors du défilement ?

Lors du défilement, le système appelle Layout et Draw pour chaque nouvel élément de la liste. Si les vues sont complexes, la mise en page n'est pas mise en cache ou des drawables lourds sont utilisés — le temps d'image augmente et le FPS chute. La solution est le recyclage des ViewHolder et une hiérarchie plate.

Comment mesurer le FPS sur iOS ?

Utilisez Instruments avec le modèle Core Animation (affiche le FPS en temps réel). Pour une mesure programmatique — CADisplayLink avec comptage d'images par seconde. Pour la production — MetricKit avec la métrique MXAnimatoryMetric.

Qu'est-ce que le Triple Buffering et comment affecte-t-il le FPS ?

Triple Buffering utilise trois tampons au lieu de deux, permettant au GPU de commencer à rendre l'image suivante avant la fin du VSync actuel. Cela lisse les pics de charge et améliore la stabilité du FPS, mais ajoute une image de latence.

Résumé

  • FPS est la métrique clé de la fluidité de l'interface, la valeur cible est de 60 images par seconde.
  • Le temps d'image est un indicateur plus précis que le FPS, en particulier les percentiles P95 et P99.
  • Pour les écrans 120 Hz, 120 FPS sont requis avec un budget de 8,3 ms par image.
  • Les principales causes de chute de FPS sont le overdraw, l'imbrication profonde des vues et les allocations dans le cycle de dessin.
  • Frame Pacing et Triple Buffering aident à lisser l'irrégularité du temps d'image.
  • Profilage FPS — via GPU Profiling (Android), Instruments Core Animation (iOS), Firebase Performance.
  • La surveillance du P95 Frame Time en production est essentielle pour identifier les régressions avant les plaintes massives des utilisateurs.

Nous développerons une application mobile clé en main

IT Sectr crée des applications iOS et Android pour les startups et les entreprises depuis 2017. Nous vous conseillerons et vous proposerons la meilleure solution.

Discuter du projet

Lisez aussi