FPS (Frames Per Second) — je metrika ukazující, kolik jednotlivých snímků grafický systém vykreslí za jednu sekundu. V mobilním vývoji je FPS standardním ukazatelem výkonu UI: čím vyšší FPS, tím plynulejší animace a responzivnější rozhraní. Podle údajů Google Android Performance, 2025 je cílová hodnota FPS pro mobilní aplikace 60 snímků za sekundu — to je práh, při kterém lidské oko vnímá pohyb jako spojitý a plynulý.
Hlavní body
FPS (Frames Per Second) — je jednotka měření snímkové frekvence používaná v počítačové grafice, videu a mobilních rozhraních. Každý snímek je statický obraz zobrazený na obrazovce po krátkou dobu. Při rychlém střídání snímků je mozek vnímá jako spojitý pohyb — tento efekt se nazývá perzistence vidění. Pro mobilní aplikace je FPS kritickou metrikou, protože každý zmeškaný snímek (drop) mění plynulou animaci na znatelné škubnutí. Aplikace musí stihnout vykreslit každý snímek přesně v rámci časového rozpočtu: 16.6 ms pro 60 FPS, 11.1 ms pro 90 FPS, 8.3 ms pro 120 FPS.
FPS se měří nejen pro UI, ale také pro hry, video a kameru. Ve hrách FPS závisí na složitosti scény, kvalitě textur a výkonu GPU. Ve videu je FPS pevný (24, 30, 60 snímků/s) a je určen obsahem. V mobilních aplikacích FPS závisí na efektivitě UI kódu: složitosti Layoutu, počtu View, frekvenci překreslování a činnosti GC (Garbage Collection). Podle Apple WWDC 2022 může průměrné FPS v aplikaci klesnout o 10–15 % kvůli neefektivní aktualizaci kolekcí (reloadData místo insert/delete/dequeueReusableCell). Měření FPS v reálném čase je standardní praxí pro QA inženýry a vývojáře pracující na výkonu.
Výpočet FPS v mobilní aplikaci je založen na měření času mezi po sobě jdoucími snímky. Nejjednodušší vzorec: FPS = 1000 / deltaTimeMs, kde deltaTimeMs je interval mezi dokončením předchozího snímku a dokončením aktuálního. Pokud byl aktuální snímek vykreslen za 20 ms, FPS = 1000 / 20 = 50. V praxi je však FPS málokdy stabilní ani během jedné sekundy: typický profil zahrnuje snímky o délce 12–16 ms proložené zmeškanými (jank) nebo pomalými snímky (40–60 ms). Proto se FPS měří jako klouzavý průměr za 1–5 sekund nebo jako percentily rozložení času snímků.
V Androidu se FPS počítá prostřednictvím Choreographer, který přijímá callback z VSync (impuls synchronizace displeje). Každý callback odpovídá jednomu snímku. Pokud callback nepřišel — snímek byl zmeškán. Choreographer umožňuje přesně měřit počet snímků za sekundu a počet zmeškaných (skipped frames). V iOS funguje CADisplayLink analogicky — je volán pokaždé, když je displej připraven vykreslit nový snímek. Vlastnost timestamp obsahuje přesný čas posledního snímku a targetTimestamp — očekávaný čas dalšího. Rozdíl mezi nimi je časový rozpočet pro aktuální snímek.
Kód ve Swiftu demonstruje jednoduché monitorování FPS přes CADisplayLink. Počitadlo frameCount se zvyšuje při každém volání a jednou za sekundu se vypočítá skutečné FPS.
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
}
}
}
Standard 60 FPS (60 Hz) se v průmyslu upevnil z několika důvodů. První — fyziologický: lidské oko nerozlišuje jednotlivé snímky při frekvenci nad 50–60 Hz a vnímá je jako plynulý pohyb. Tento práh se nazývá Critical Flicker Fusion (CFF). Druhý — historický: první katodové trubice (CRT) pracovaly na 60 Hz v USA (NTSC) a 50 Hz v Evropě (PAL). Moderní LCD displeje tuto frekvenci zdědily. Třetí — inženýrský: pro UI animace poskytuje 60 FPS submilisekundovou odezvu na dotyk, což je kritické pro zadávání textu, scrollování a přetahování.
Pro mobilní vývojáře není 60 FPS jen doporučení, ale přísný rozpočet 16.6 ms na snímek. Tento rozpočet je rozdělen mezi všechny fáze vykreslování: Input (1–2 ms), Animation (2–3 ms), Layout (3–5 ms), Draw (3–5 ms) a Swap (1–2 ms). Pokud některá fáze překročí svůj pod-rozpočet, snímek se nemusí vejít do 16.6 ms. Google Android Performance doporučuje vejít se do 12–14 ms na přípravu snímku, s rezervou 2–4 ms pro systémová přerušení (GC, vlákna na pozadí). Podle Firebase Performance dostávají aplikace s průměrným FPS pod 52 a P99 FPS pod 30 o 35 % více stížností na výkon v recenzích Google Play.
FPS a Frame Time (čas snímku) — jsou dvě strany téže metriky a je důležité je nezaměňovat. FPS je rychlost, Frame Time je zpoždění. Při 60 FPS trvá každý snímek 16.6 ms. Při 30 FPS — 33.3 ms. Ale FPS je nelineární metrika: pokles z 60 na 30 FPS znamená, že se čas snímku zdvojnásobil, a pokles z 30 na 20 — 1.5krát. Proto profilery nezobrazují FPS, ale Frame Time — to umožňuje vidět problémové snímky, nikoli průměrnou frekvenci. Například průměr 55 FPS může skrývat, že 5 % snímků má Frame Time 50–100 ms — tyto snímky způsobují Jank, ale příliš neovlivňují průměrné FPS.
Při analýze výkonu se doporučuje dívat se nikoli na průměrné FPS, ale na histogram Frame Time. V Android Studio Profiler a iOS Instruments je Frame Time zobrazen jako stupnice, kde zelená zóna — do 16.6 ms (60 FPS), žlutá — 16.6–33.3 ms (30–60 FPS), červená — nad 33.3 ms (pod 30 FPS). Každý červený sloupec je pro uživatele znatelné zpoždění. Praktické pravidlo: P95 Frame Time (95 % snímků se vejde do X ms) — je spolehlivější metrika než průměrné FPS. Pokud P95 Frame Time překročí 32 ms (30 FPS), aplikace je vnímána jako pomalá i při průměrném FPS = 50.
Funkce v Kotlinu pro konverzi pole časů snímků na FPS s percentily. Vrací nejen průměrné FPS, ale také P50, P90 a P99 pro podrobnou analýzu.
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)]
)
}
Moderní mobilní zařízení s displeji 90, 120 a 144 Hz kladou nové nároky na FPS. Pokud aplikace dodává 60 FPS na 120Hz displeji, uživatel vidí mikro-zadrhávání, protože každý druhý cyklus obnovování obrazovky dostává stejný snímek. Pro udržení 120 FPS se rozpočet na snímek snižuje z 16.6 na 8.3 ms — to vyžaduje dvojnásobně efektivní kód vykreslování. Podle vývojářů Androidu (Google I/O 2023) je pro dosažení stabilních 120 FPS nutné: vyhnout se alokacím v Draw cyklu, minimalizovat počet View v hierarchii (méně než 80), upustit od těžkých drawable ve prospěch VectorDrawable a používat surfaceView pro složitou grafiku.
V iOS je situace analogická: iPhone Pro s ProMotion (120 Hz) vyžaduje dvojnásobný počet snímků, ale čas na každý snímek je poloviční. Apple poznamenává, že ne všechny animace musí běžet na 120 FPS — Core Animation automaticky snižuje frekvenci pro statické nebo pomalu se měnící prvky. Nicméně scrollování, gesta animací a přechody by měly dodávat 120 FPS pro pocit "hedvábnosti". Hlavní problémy při přechodu z 60 na 120 FPS: zvýšení spotřeby energie (o 25–40 % pro GPU), zahřívání zařízení a throttling — kdy frekvence klesá kvůli přehřívání. Doporučuje se implementovat fallback mechanismus: pokud Frame Time stabilně překračuje 8.3 ms, programově snížit cílovou frekvenci na 60 FPS, místo čekání na systémový throttling.
Kód v Javě pro Android určuje, zda zařízení podporuje 120 FPS, a přepíná režim vykreslování. Používá Display.getMode k určení podporovaných frekvencí.
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;
}
}
Optimalizace FPS vyžaduje systematický přístup, počínaje profilováním a konče refaktorováním problematických míst. První fáze — změřit aktuální FPS pomocí profilovacího nástroje (. Druhá fáze — najít snímky přesahující rozpočet. Pro Android to lze provést pomocí GPU Profiling nebo Perfetto. Pro iOS — Instruments se šablonou Core Animation. Třetí fáze — odstranit příčiny: snížit overdraw, snížit hloubku vnoření View, nahradit fázi Layout pomocí ConstraintLayout, přidat ViewHolder Recycling, přesunout těžké výpočty na vlákno na pozadí.
Specifické optimalizace FPS zahrnují: Frame Pacing — mechanismus, který rovnoměrně rozkládá čas mezi snímky, aby se zabránilo "balíčkům" rychlých a pomalých snímků. V Androidu umožňuje Choreographer.FrameCallback s pevným intervalem implementovat Frame Pacing. V iOS dělá totéž CADisplayLink.preferredFrameRateRange. Druhý mechanismus — Triple Buffering: systém používá tři buffery místo dvou, což umožňuje GPU začít kreslit další snímek, aniž by čekal na uvolnění předchozího. Android automaticky zapíná Triple Buffering v případě potřeby, ale v iOS o něj může vývojář výslovně požádat prostřednictvím CAMetalLayer. Třetí — Texture Caching: ukládání bitmap do paměti GPU, aby se nemusely znovu načítat při každém snímku.
Příklad v Kotlinu demonstruje implementaci Frame Pacing s pevným intervalem 16.6 ms. Všechny callbacky přicházejí s rovnoměrným intervalem, i když systém zpožďuje.
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) {
// vykreslení snímku
}
}
Často kladené otázky
60 FPS — pohodlná úroveň pro mobilní aplikace. Rozdíl mezi 60 a 120 FPS je patrný pouze na displejích s vysokou obnovovací frekvencí při rychlých animacích (scrollování, přetahování). Pod 30 FPS — nepohodlí.
FPS = 1000 / FrameTime (ms). Pokud Frame Time = 16.6 ms, FPS = 60. Pokud Frame Time = 33.3 ms, FPS = 30. Doporučuje se monitorovat Frame Time, ne FPS, protože ukazuje problémové snímky.
Při scrollování systém volá Layout a Draw pro každý nový prvek seznamu. Pokud jsou View složitá, Layout není kešován nebo se používají těžké drawable — Frame Time roste a FPS klesá. Řešení — ViewHolder recycling a plochá hierarchie.
Použijte Instruments se šablonou Core Animation (zobrazuje FPS v reálném čase). Pro programové měření — CADisplayLink s počítáním snímků za sekundu. Pro produkci — MetricKit s metrikou MXAnimatoryMetric.
Triple Buffering používá tři buffery místo dvou, což umožňuje GPU začít vykreslovat další snímek před dokončením VSync aktuálního. To vyhlazuje špičkové zatížení a zvyšuje stabilitu FPS, ale přidává zpoždění 1 snímku.
Shrnutí
Vyvineme mobilní aplikaci na klíč
IT Sectr vytváří aplikace pro iOS a Android pro startupy a podniky od roku 2017. Poradíme vám a navrhneme nejlepší řešení.
Přečtěte si také