FPS (Frames Per Second) ist eine Metrik, die zeigt, wie viele Einzelbilder ein Grafiksystem in einer Sekunde rendert. In der mobilen Entwicklung ist FPS ein Standardindikator für die UI-Leistung: Je höher die FPS, desto flüssiger die Animationen und desto reaktionsschneller die Benutzeroberfläche. Laut Google Android Performance, 2025 beträgt der Zielwert für FPS in mobilen Apps 60 Bilder pro Sekunde — die Schwelle, ab der das menschliche Auge Bewegung als kontinuierlich und fließend wahrnimmt.
Wichtige Erkenntnisse
FPS (Frames Per Second) ist eine Maßeinheit für die Bildrate, die in Computergrafik, Video und mobilen Oberflächen verwendet wird. Jedes Bild ist ein statisches Bild, das für kurze Zeit auf dem Bildschirm angezeigt wird. Bei schnellen Bildwechseln nimmt das Gehirn sie als kontinuierliche Bewegung wahr — dieser Effekt wird als Nachbildwirkung bezeichnet. Für mobile Anwendungen ist FPS eine kritische Metrik, da jedes ausgelassene Bild eine flüssige Animation in ein spürbares Ruckeln verwandelt. Die Anwendung muss jedes Bild strikt innerhalb des Zeitbudgets rendern: 16,6 ms für 60 FPS, 11,1 ms für 90 FPS, 8,3 ms für 120 FPS.
FPS wird nicht nur für die Benutzeroberfläche, sondern auch für Spiele, Video und Kamera gemessen. Bei Spielen hängt FPS von der Szenenkomplexität, der Texturqualität und der GPU-Leistung ab. Bei Video ist FPS festgelegt (24, 30, 60 fps) und wird durch den Inhalt bestimmt. Bei mobilen Anwendungen hängt FPS von der Effizienz des UI-Codes ab: Layout-Komplexität, Anzahl der Views, Häufigkeit von Neuzeichnungen und Arbeit des GC (Garbage Collection). Laut Apple WWDC 2022 kann die durchschnittliche FPS in einer Anwendung aufgrund ineffizienter Sammlungsaktualisierungen (reloadData statt insert/delete/dequeueReusableCell) um 10–15% sinken. Die Messung von FPS in Echtzeit ist eine Standardpraxis für QA-Ingenieure und Entwickler, die an der Leistung arbeiten.
Die Berechnung von FPS in einer mobilen Anwendung basiert auf der Messung der Zeit zwischen aufeinanderfolgenden Bildern. Die einfachste Formel: FPS = 1000 / deltaTimeMs, wobei deltaTimeMs das Intervall zwischen dem Abschluss des vorherigen Bildes und dem Abschluss des aktuellen ist. Wenn das aktuelle Bild in 20 ms gerendert wurde, FPS = 1000 / 20 = 50. In der Praxis ist FPS jedoch selbst innerhalb einer Sekunde selten stabil: Ein typisches Profil enthält Bilder von 12–16 ms, die mit ausgelassenen (Jank) oder langsamen Bildern (40–60 ms) durchsetzt sind. Daher wird FPS als gleitender Durchschnitt über 1–5 Sekunden oder als Perzentile der Bildzeitverteilung gemessen.
Unter Android wird FPS über Choreographer berechnet, der einen Rückruf von VSync (Display-Synchronisationsimpuls) erhält. Jeder Rückruf entspricht einem Bild. Wenn der Rückruf nicht eintrifft, wird das Bild ausgelassen. Choreographer ermöglicht die Messung der genauen Anzahl von Bildern pro Sekunde und der Anzahl ausgelassener Bilder. Unter iOS funktioniert CADisplayLink ähnlich — es wird jedes Mal aufgerufen, wenn das Display bereit ist, ein neues Bild zu rendern. Die Eigenschaft timestamp enthält die genaue Zeit des letzten Bildes und targetTimestamp die erwartete Zeit des nächsten. Die Differenz zwischen ihnen ist das Zeitbudget für das aktuelle Bild.
Swift-Code demonstriert eine einfache FPS-Überwachung über CADisplayLink. Der Zähler frameCount wird bei jedem Aufruf erhöht, und einmal pro Sekunde wird die tatsächliche FPS berechnet.
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
}
}
}
Der 60 FPS (oder 60 Hz) Standard hat sich aus mehreren Gründen in der Industrie etabliert. Der erste ist physiologisch: Das menschliche Auge unterscheidet keine einzelnen Bilder bei Frequenzen über 50–60 Hz und nimmt sie als fließende Bewegung wahr. Diese Schwelle wird als Critical Flicker Fusion (CFF) bezeichnet. Der zweite ist historisch: Frühe Kathodenstrahlröhren (CRT) arbeiteten in den USA (NTSC) mit 60 Hz und in Europa (PAL) mit 50 Hz. Moderne LCD-Displays haben diese Frequenz geerbt. Der dritte ist technisch: Für UI-Animationen bietet 60 FPS eine Submillisekunden-Berührungsreaktionslatenz, die für Texteingabe, Scrollen und Ziehen entscheidend ist.
Für mobile Entwickler ist 60 FPS nicht nur eine Empfehlung, sondern ein strenges Budget von 16,6 ms pro Bild. Dieses Budget verteilt sich auf alle Renderphasen: Eingabe (1–2 ms), Animation (2–3 ms), Layout (3–5 ms), Zeichnen (3–5 ms) und Austausch (1–2 ms). Wenn eine Phase ihr Teilbudget überschreitet, passt das Bild möglicherweise nicht in 16,6 ms. Google Android Performance empfiehlt, für die Bildvorbereitung innerhalb von 12–14 ms zu bleiben und 2–4 ms Spielraum für Systemunterbrechungen (GC, Hintergrund-Threads) zu lassen. Laut Firebase Performance erhalten Anwendungen mit einer durchschnittlichen FPS unter 52 und P99 FPS unter 30 35% mehr Leistungsbeschwerden in Google Play-Bewertungen.
FPS und Bildzeit sind zwei Seiten derselben Metrik, und es ist wichtig, sie nicht zu verwechseln. FPS ist Geschwindigkeit, Bildzeit ist Latenz. Bei 60 FPS dauert jedes Bild 16,6 ms. Bei 30 FPS — 33,3 ms. Aber FPS ist eine nichtlineare Metrik: Ein Abfall von 60 auf 30 FPS bedeutet, dass sich die Bildzeit verdoppelt hat, während ein Abfall von 30 auf 20 eine 1,5-fache Erhöhung bedeutet. Daher zeigen Profiler die Bildzeit anstelle von FPS — dies ermöglicht das Erkennen problematischer Bilder anstelle einer gemittelten Frequenz. Zum Beispiel kann ein Durchschnitt von 55 FPS verbergen, dass 5% der Bilder eine Bildzeit von 50–100 ms haben — diese Bilder verursachen Jank, beeinflussen aber die durchschnittliche FPS nicht wesentlich.
Bei der Leistungsanalyse wird empfohlen, nicht auf die durchschnittliche FPS zu schauen, sondern auf das Bildzeit-Histogramm. Im Android Studio Profiler und in iOS Instruments wird die Bildzeit als Skala angezeigt, wobei die grüne Zone bis 16,6 ms (60 FPS), gelb von 16,6–33,3 ms (30–60 FPS) und rot über 33,3 ms (weniger als 30 FPS) reicht. Jede rote Spalte ist eine spürbare Verzögerung für den Benutzer. Eine praktische Regel: P95-Bildzeit (95% der Bilder passen in X ms) ist eine zuverlässigere Metrik als die durchschnittliche FPS. Wenn die P95-Bildzeit 32 ms (30 FPS) überschreitet, fühlt sich die Anwendung selbst bei einer durchschnittlichen FPS von 50 träge an.
Eine Kotlin-Funktion zum Konvertieren eines Arrays von Bildzeiten in FPS mit Perzentilen. Sie gibt nicht nur die durchschnittliche FPS zurück, sondern auch P50, P90 und P99 für eine detaillierte Analyse.
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)]
)
}
Moderne mobile Geräte mit 90, 120 und 144 Hz Displays stellen neue Anforderungen an FPS. Wenn eine Anwendung 60 FPS auf einem 120 Hz Display liefert, sieht der Benutzer Mikroruckler, weil jeder zweite Bildschirmaktualisierungszyklus dasselbe Bild erhält. Um 120 FPS zu halten, schrumpft das Budget pro Bild von 16,6 auf 8,3 ms — was einen doppelt so effizienten Rendering-Code erfordert. Laut Android-Entwicklern (Google I/O 2023) sind für stabile 120 FPS erforderlich: Vermeidung von Allokationen im Zeichenzyklus, Minimierung der Anzahl von Views in der Hierarchie (unter 80), Ersetzen schwerer Drawables durch VectorDrawable und Verwendung von surfaceView für komplexe Grafiken.
Die Situation ist unter iOS ähnlich: Das iPhone Pro mit ProMotion (120 Hz) benötigt doppelt so viele Bilder, aber die Zeit pro Bild ist halbiert. Apple stellt fest, dass nicht alle Animationen mit 120 FPS laufen müssen — Core Animation reduziert automatisch die Bildrate für statische oder sich langsam ändernde Elemente. Allerdings müssen Scrollen, Gestenanimationen und Übergänge 120 FPS für ein „seidiges“ Gefühl liefern. Die Hauptprobleme beim Übergang von 60 auf 120 FPS: erhöhter Stromverbrauch (25–40% für die GPU), Geräteerwärmung und Drosselung — wenn die Bildrate durch Überhitzung abfällt. Es wird empfohlen, einen Fallback-Mechanismus zu implementieren: Wenn die Bildzeit konstant 8,3 ms überschreitet, die Zielbildrate programmatisch auf 60 FPS senken, anstatt auf die Systemdrosselung zu warten.
Java-Code für Android bestimmt, ob das Gerät 120 FPS unterstützen kann, und schaltet den Rendermodus um. Display.getMode wird verwendet, um die unterstützten Bildwiederholraten zu ermitteln.
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;
}
}
Die Optimierung von FPS erfordert einen systematischen Ansatz, der mit der Profilerstellung beginnt und mit der Refaktorisierung problematischer Bereiche endet. Der erste Schritt ist die Messung der aktuellen FPS mit einem Profiler. Der zweite Schritt ist das Auffinden von Bildern, die das Budget überschreiten. Unter Android kann dies über GPU Profiling oder Perfetto erfolgen. Unter iOS — Instruments mit der Core Animation-Vorlage. Der dritte Schritt ist die Beseitigung der Ursachen: Reduzierung von Overdraw, Verringerung der View-Hierarchietiefe, Ersetzen der Layout-Phase durch ConstraintLayout, Hinzufügen von ViewHolder Recycling und Verschieben schwerer Berechnungen in einen Hintergrund-Thread.
Spezifische FPS-Optimierungen umfassen: Frame Pacing — ein Mechanismus, der die Zeit gleichmäßig zwischen den Bildern verteilt, um „Ausbrüche“ von schnellen und langsamen Bildern zu vermeiden. Unter Android ermöglicht Choreographer.FrameCallback mit einem festen Intervall die Implementierung von Frame Pacing. Unter iOS macht CADisplayLink.preferredFrameRateRange dasselbe. Die zweite Methode — Triple Buffering: Das System verwendet drei Puffer statt zwei, sodass die GPU mit dem Rendern des nächsten Bildes beginnen kann, ohne auf die Freigabe des vorherigen warten zu müssen. Android aktiviert Triple Buffering bei Bedarf automatisch, aber unter iOS kann der Entwickler es explizit über CAMetalLayer anfordern. Die dritte — Texture Caching: Zwischenspeichern von Bitmaps im GPU-Speicher, um ein erneutes Laden bei jedem Bild zu vermeiden.
Ein Kotlin-Beispiel demonstriert die Implementierung von Frame Pacing mit einem festen Intervall von 16,6 ms. Alle Rückrufe treffen in einem gleichmäßigen Intervall ein, selbst wenn das System verzögert ist.
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) {
// Bild-Rendering
}
}
Häufig gestellte Fragen
60 FPS ist ein angenehmes Niveau für mobile Anwendungen. Der Unterschied zwischen 60 und 120 FPS ist nur auf Displays mit hoher Bildwiederholrate bei schnellen Animationen (Scrollen, Ziehen) spürbar. Unter 30 FPS — unangenehm.
FPS = 1000 / FrameTime (ms). Wenn die Bildzeit = 16,6 ms, FPS = 60. Wenn die Bildzeit = 33,3 ms, FPS = 30. Es wird empfohlen, die Bildzeit anstelle von FPS zu überwachen, da sie problematische Bilder anzeigt.
Beim Scrollen ruft das System Layout und Draw für jedes neue Listenelement auf. Wenn Views komplex sind, Layout nicht zwischengespeichert wird oder schwere Drawables verwendet werden — steigt die Bildzeit und die FPS fallen. Die Lösung ist ViewHolder-Recycling und eine flache Hierarchie.
Verwenden Sie Instruments mit der Core Animation-Vorlage (zeigt FPS in Echtzeit). Für programmatische Messung — CADisplayLink mit Bildzählung pro Sekunde. Für die Produktion — MetricKit mit der Metrik MXAnimatoryMetric.
Triple Buffering verwendet drei Puffer statt zwei, sodass die GPU mit dem Rendern des nächsten Bildes beginnen kann, bevor der aktuelle VSync abgeschlossen ist. Dies glättet Spitzenlasten und verbessert die FPS-Stabilität, fügt jedoch eine Bildlatenz hinzu.
Zusammenfassung
Wir entwickeln eine mobile Applikation schlüsselfertig
IT Sectr entwickelt seit 2017 iOS- und Android-Apps für Startups und Unternehmen. Wir beraten Sie und schlagen die beste Lösung vor.
Lesen Sie auch