Le Frame Rate est le nombre d'images qu'un système graphique affiche par seconde. Dans les applications mobiles, la fréquence d'images détermine directement la fluidité des animations, du défilement et des transitions entre écrans. Selon Android Developers, 2025, le Frame Rate cible est de 60 fps pour les écrans standard et de 120 fps pour les appareils à taux de rafraîchissement élevé. Un écart par rapport à la valeur cible entraîne un bégaiement visuel et une dégradation de l'expérience utilisateur.
Points clés
Frame Rate (fréquence d'images) est une métrique mesurée en images par seconde (fps) qui indique combien de fois par seconde une application met à jour l'image à l'écran. L'œil humain perçoit le mouvement comme fluide à partir de 24 fps (cinéma), mais une interface interactive nécessite au moins 60 fps pour que les touches et les animations paraissent instantanées. Chaque image est un cycle complet : traitement de l'entrée utilisateur, calcul du Layout, rendu de la hiérarchie des vues et sortie vers l'écran. Si l'une de ces étapes dépasse le budget de temps alloué (16,6 ms à 60 fps), l'image est sautée et l'utilisateur voit un bégaiement.
Il est important de distinguer le Frame Rate de l'application du taux de rafraîchissement de l'écran (Refresh Rate). Le taux de rafraîchissement est une caractéristique matérielle : combien de fois par seconde l'écran met physiquement à jour l'image (60, 90, 120 ou 144 Hz). Le Frame Rate est le nombre d'images par seconde que l'application parvient à rendre. Si l'application produit 60 fps sur un écran 120 Hz, une image sur deux sera dupliquée — l'image reste fluide mais pas aussi réactive qu'elle pourrait l'être. Selon Google I/O 2023, les flagships modernes peuvent maintenir 120 fps dans des scénarios d'interface simples, mais sous charge lourde (jeux, listes complexes) le taux tombe à 40–60 fps.
Le rendu des images dans une application mobile passe par un pipeline de plusieurs étapes. Sous Android, le pipeline comprend : le traitement des entrées (Input), l'animation (Animation), la mesure et la disposition (Layout), le dessin (Draw), la synchronisation GPU et la sortie écran (Swap). Chaque étape s'exécute sur le CPU ou le GPU, et le temps total de toutes les étapes ne doit pas dépasser le budget de l'image. Pour 60 fps, le budget est de 16,6 ms, pour 120 fps — 8,3 ms. Choreographer (Android) et CADisplayLink (iOS) synchronisent le rendu avec l'intervalle de blanking vertical de l'écran (VSync), garantissant que l'image n'est affichée qu'au moment du rafraîchissement de l'écran, évitant le tearing.
Sous iOS, le pipeline est similaire : Run Loop traite les événements, Core Animation calcule les couches, Render Server (un processus séparé) effectue le rendu et envoie l'image au GPU. La différence sous iOS est le processus dédié Render Server, qui isole le rendu de l'application principale. Si l'application bloque le thread principal, Render Server peut toujours dessiner la dernière image connue, mais les animations s'arrêteront. Si Render Server lui-même ne peut pas suivre — le GPU reste inactif et le Frame Rate chute. Selon l'Apple WWDC 2022, les causes les plus fréquentes d'un faible Frame Rate sous iOS sont l'imbrication excessive de CALayer, les shadowPath lourds et le rendu hors écran.
Le code Kotlin s'abonne à Choreographer.FrameCallback et enregistre le temps réel entre les images. Si l'intervalle dépasse 16,6 ms, une image perdue est enregistrée.
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)
}
}
Refresh Rate (taux de rafraîchissement) est une caractéristique matérielle de l'écran qui détermine combien de fois par seconde l'affichage redessine physiquement l'image. Les écrans standard ont 60 Hz, les flagships modernes ont 90, 120 ou 144 Hz. Le Frame Rate de l'application peut être inférieur, égal ou supérieur au taux de rafraîchissement (dans ce dernier cas, les images en excès sont ignorées). Le scénario idéal est lorsque le Frame Rate coïncide avec le Refresh Rate : chaque cycle matériel reçoit une nouvelle image de l'application et le mouvement est maximalement fluide. Si le Frame Rate est inférieur, l'écran répète la dernière image, ce qui est perçu comme un micro-bégaiement.
Android et iOS prennent en charge le changement dynamique du taux de rafraîchissement. Android 12+ utilise Smart Refresh Rate : lors du défilement, le système élève le taux à 120 Hz, sur du contenu statique, il le réduit à 60 Hz pour économiser la batterie. iOS ProMotion (iPhone 13 Pro et plus récents) fonctionne de manière similaire — le taux varie de 10 à 120 Hz selon le contenu. Le développeur doit vérifier si l'appareil prend en charge un taux élevé et adapter le budget de temps par image. Si l'application ne peut pas rendre une image en 8,3 ms (pour 120 Hz), il est préférable de forcer 60 Hz — cela garantira un Frame Rate stable sans images perdues.
| Type d'écran | Refresh Rate | Budget par image | Appareils |
|---|---|---|---|
| Standard | 60 Hz | 16,6 ms | La plupart Android/iOS |
| Élevé | 90 Hz | 11,1 ms | OnePlus, Pixel 6+ |
| Flagship | 120 Hz | 8,3 ms | iPhone Pro, Galaxy S22+ |
| Jeu | 144 Hz | 6,9 ms | ROG Phone, Nubia RedMagic |
Les outils intégrés des plateformes ainsi que les profileurs tiers sont disponibles pour mesurer le Frame Rate dans les applications mobiles. Sous Android, l'outil principal est GPU Profiling (Developer Options → Profile GPU Rendering), qui montre une chronologie de chaque image décomposée par étapes (Draw, Prepare, Process, Execute). Une analyse plus détaillée est fournie par Android Studio Profiler — il enregistre un profil de rendu complet indiquant les vues spécifiques qui provoquent des redessins. Sous iOS, on utilise Instruments avec le modèle Core Animation — il affiche le FPS, le temps de rendu des couches et le nombre de rendus hors écran.
Pour la surveillance du Frame Rate en production, Firebase Performance (Android) est utilisé — il collecte le Frame Rate en arrière-plan et l'agrège par appareil, version d'OS et session. Sous iOS, MetricKit fournit des données similaires via MXAnimatoryMetric. Pour les jeux et les applications Flutter, on utilise FrameTimingCallback (Flutter) et Unity Profiler. Il est important de mesurer non pas le Frame Rate moyen mais les percentiles : P50, P90 et P99. Une application peut afficher une moyenne de 55 fps mais avoir un P99 de 30 fps — cela signifie que 1% du temps les utilisateurs voient un bégaiement sévère, suffisant pour des avis négatifs.
L'exemple Dart montre comment s'abonner à FrameTimingCallback dans Flutter et enregistrer le nombre d'images perdues. Le callback se déclenche après chaque image terminée.
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}");
}
}
L'optimisation du Frame Rate commence par l'identification des goulots d'étranglement dans le pipeline de rendu. Dans la phase de Layout, les principaux problèmes sont l'imbrication excessive de la hiérarchie des vues, l'utilisation de layouts relatifs (RelativeLayout avec de nombreuses règles) et les appels fréquents à requestLayout. La solution consiste à utiliser ConstraintLayout ou une hiérarchie plate, en évitant les imbrications de plus de 5 à 6 niveaux. Dans la phase de Draw — l'overdraw : lorsqu'un pixel est dessiné plusieurs fois par image. Par exemple, un fond d'Activity blanc sous un fragment semi-transparent, sous lequel se trouve encore une couche — chaque pixel est dessiné trois fois. L'outil Debug GPU Overdraw montre les zones problématiques avec un code couleur. Il est recommandé de maintenir l'overdraw à 2x ou moins.
Sous iOS, les principaux problèmes sont cornerRadius et masksToBounds lourds — ils provoquent un rendu hors écran, où Core Animation crée un tampon temporaire, dessine dedans, puis copie le résultat à l'écran. Le rendu hors écran est facilement repérable dans Instruments Core Animation : si la ligne Renderer est rouge — il y a des problèmes. La solution consiste à utiliser UIImageView avec des images pré-recadrées au lieu de cornerRadius, à éviter groupOpacity et shouldRasterize sauf en cas d'absolue nécessité. Pour les deux plateformes, il est essentiel de minimiser le nombre d'appels à invalidate() et setNeedsDisplay() — chacun de ces appels déclenche un cycle complet de redessin de la vue.
Le code montre le remplacement d'une imbrication profonde de RelativeLayout par une structure plate avec ConstraintLayout. La réduction du niveau d'imbrication de 4 à 1 réduit le temps de Layout de 30 à 50%.
// Exemple : structure plate via 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
// lier les données sans redessiner tout le conteneur
}
}
Les applications mobiles modernes utilisent de plus en plus le Frame Rate adaptatif — un système qui ajuste dynamiquement la fréquence cible en fonction du scénario actuel. Un défilement rapide nécessite 120 fps pour la fluidité, tandis qu'un écran statique n'a besoin que de 60 fps voire 30 fps pour une vidéo. Sous Android, l'adaptation est implémentée via Choreographer.setFrameInterval (API 33+) et Window.setFrameRate. Le développeur peut spécifier une fréquence préférée : setPreferredRefreshRate dans SurfaceView ou setFrameRate dans Window. iOS gère automatiquement la fréquence via ProMotion, mais le développeur peut définir explicitement preferredFramesPerSecond pour CADisplayLink.
Le Dynamic Frame Rate est particulièrement important pour les jeux et les applications avec animations. Selon Google, réduire le Frame Rate de 120 à 60 Hz sur un écran statique économise jusqu'à 30 à 40% d'énergie GPU. Pour atteindre le meilleur équilibre entre fluidité et consommation d'énergie, il est recommandé de : mesurer le Frame Rate réel dans différents scénarios, définir les fps cibles en fonction de la scène (jeu — 60, menu — 30, vidéo — 24), et changer les modes via des composants Lifecycle-aware pour que l'application ne gaspille pas de ressources à rendre du 120 fps en arrière-plan lorsqu'elle est minimisée.
Le code Swift définit preferredFramesPerSecond pour CADisplayLink sous iOS. Lors du défilement, la fréquence monte à 120 Hz, à l'arrêt elle descend à 60 Hz.
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() {
// mise à jour d'animation
}
}
Questions fréquentes
Pour les applications mobiles, le Frame Rate cible est de 60 fps (16,6 ms par image). Pour les appareils avec écrans 120 Hz, 120 fps sont souhaitables. Les valeurs inférieures à 30 fps dégradent notablement l'expérience utilisateur.
Frame Rate — nombre d'images par seconde que l'application rend. Refresh Rate — nombre de fois par seconde que l'écran met physiquement à jour l'image. Lorsque le Frame Rate est inférieur au Refresh Rate, l'écran duplique la dernière image.
Utilisez GPU Profiling dans les options développeur, Android Studio Profiler ou Firebase Performance. Pour une mesure programmatique — Choreographer.FrameCallback avec calcul de l'intervalle entre les images.
Overdraw — dessiner un même pixel plusieurs fois par image. Chaque couche supplémentaire augmente le temps de la phase Draw et réduit le Frame Rate. L'overdraw optimal est de 2x, le critique est de 4x et plus.
Sur du contenu statique, le Dynamic Frame Rate réduit la fréquence à 30–60 Hz, diminuant la charge du GPU de 30 à 40%. Lors du défilement, la fréquence monte à 90–120 Hz pour la fluidité.
Résumé
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.
Lisez aussi