Frame Rate w aplikacjach mobilnych — co to jest, fps i jak poprawić

Autor: IT Sectr Opublikowano: 2026-03-31 Czas czytania: 10 min

Frame Rate — to liczba klatek, którą system graficzny wyświetla w ciągu jednej sekundy. W aplikacjach mobilnych częstotliwość klatek bezpośrednio określa płynność animacji, przewijania i przejść między ekranami. Według danych Android Developers, 2025, docelowy Frame Rate wynosi 60 fps dla standardowych wyświetlaczy i 120 fps dla urządzeń z wysoką częstotliwością odświeżania. Odchylenie od docelowej wartości prowadzi do wizualnych zacięć i pogorszenia doświadczenia użytkownika.

Najważniejsze

  • Frame Rate — liczba klatek na sekundę (fps), określająca płynność UI.
  • Standardowy docelowy Frame Rate — 60 fps, odpowiada 16.6 ms na klatkę.
  • Urządzenia z wyświetlaczami 120 Hz wymagają 120 fps (8.3 ms na klatkę).
  • Pominięte klatki powodują Jank — zauważalne zacięcia animacji.
  • Profilowanie Frame Rate — pierwszy krok do optymalizacji wydajności UI.

Co to jest Frame Rate

Frame Rate (częstotliwość klatek) — to metryka mierzona w klatkach na sekundę (fps), która pokazuje, ile razy na sekundę aplikacja aktualizuje obraz na ekranie. Ludzkie oko postrzega ruch jako płynny przy częstotliwości od 24 fps (kino), ale dla interaktywnego UI wymagane jest minimum 60 fps, aby dotknięcia i animacje były odczuwalne jako natychmiastowe. Każda klatka to pełny cykl: przetwarzanie danych wejściowych użytkownika, obliczanie Layout, renderowanie hierarchii View i wyświetlenie na ekranie. Jeśli któryś z etapów przekroczy przydzielony budżet czasu (16.6 ms przy 60 fps), klatka jest pomijana, a użytkownik widzi zacięcie.

Ważne jest rozróżnienie Frame Rate aplikacji od częstotliwości odświeżania wyświetlacza (Refresh Rate). Częstotliwość odświeżania to cecha ekranu: ile razy na sekundę wyświetlacz fizycznie odświeża obraz (60, 90, 120 lub 144 Hz). Frame Rate — to ile klatek na sekundę udaje się wyrenderować aplikacji. Jeśli aplikacja generuje 60 fps przy wyświetlaczu 120 Hz, co druga klatka będzie powielana — obraz pozostanie płynny, ale nie tak responsywny, jak mógłby być. Według danych Google I/O 2023, nowoczesne flagowce są w stanie utrzymać 120 fps w prostych scenariuszach UI, ale w ciężkich (gry, złożone listy) częstotliwość spada do 40–60 fps.

Jak działa renderowanie klatek

Renderowanie klatki w aplikacji mobilnej przechodzi przez potok składający się z kilku etapów. W Androidzie potok obejmuje: przetwarzanie danych wejściowych (Input), animację (Animation), pomiar i rozmieszczenie (Layout), rysowanie (Draw), synchronizację z GPU i wyświetlenie na ekranie (Swap). Każdy etap jest wykonywany na CPU lub GPU, a łączny czas wszystkich etapów nie powinien przekraczać budżetu klatki. Dla 60 fps budżet wynosi 16.6 ms, dla 120 fps — 8.3 ms. Choreographer (Android) i CADisplayLink (iOS) synchronizują renderowanie z pionowym odświeżaniem wyświetlacza (VSync), gwarantując, że klatka jest wyświetlana tylko w momencie odświeżania ekranu, unikając tearingu (rozerwania obrazu).

W iOS potok jest podobny: Run Loop przetwarza zdarzenia, Core Animation oblicza warstwy, Render Server (oddzielny proces) renderuje i wysyła klatkę do GPU. Różnicą w iOS jest wydzielony proces Render Server, który izoluje renderowanie od głównej aplikacji. Jeśli aplikacja blokuje główny wątek, Render Server nadal może wyświetlić ostatnią znaną klatkę, ale animacje zatrzymają się. Jeśli natomiast Render Server sam nie nadąża — GPU marnuje czas, a Frame Rate spada. Według danych Apple WWDC 2022, najczęstszymi przyczynami niskiego Frame Rate w iOS są nadmierne zagnieżdżenie CALayer, ciężkie shadowPath i renderowanie poza ekranem (offscreen rendering).

Śledzenie klatek przez Choreographer

Kod w Kotlin subskrybuje Choreographer.FrameCallback i loguje rzeczywisty czas między klatkami. Jeśli interwał przekracza 16.6 ms — rejestrowana jest pominięta klatka.

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)
    }
}

Częstotliwość odświeżania wyświetlacza a Frame Rate

Refresh Rate (częstotliwość odświeżania) — to cecha sprzętowa wyświetlacza, określająca ile razy na sekundę ekran fizycznie przerysowuje obraz. Standardowe wyświetlacze mają 60 Hz, nowoczesne flagowce — 90, 120 lub 144 Hz. Frame Rate aplikacji może być niższy, równy lub wyższy od częstotliwości odświeżania (w ostatnim przypadku nadmiarowe klatki są odrzucane). Idealny scenariusz — Frame Rate pokrywa się z Refresh Rate: każdy cykl sprzętowy otrzymuje nową klatkę od aplikacji, a ruch jest maksymalnie płynny. Jeśli Frame Rate jest niższy, wyświetlacz powtarza ostatnią klatkę, co jest odbierane jako mikro-zacięcia (stutter).

Android i iOS obsługują dynamiczne przełączanie częstotliwości odświeżania. Android 12+ używa Smart Refresh Rate: podczas przewijania system podnosi częstotliwość do 120 Hz, przy statycznej treści obniża do 60 Hz w celu oszczędzania baterii. iOS ProMotion (iPhone 13 Pro i nowsze) działa podobnie — częstotliwość waha się od 10 do 120 Hz w zależności od treści. Deweloper powinien sprawdzać, czy urządzenie obsługuje wysoką częstotliwość, i dostosowywać budżet czasu na klatkę. Jeśli aplikacja nie nadąża wyrenderować klatki w 8.3 ms (dla 120 Hz), lepiej wymusić pracę na 60 Hz — zapewni to stabilny Frame Rate bez pominiętych klatek.

Typ wyświetlaczaRefresh RateBudżet na klatkęUrządzenia
Standardowy60 Hz16.6 msWiększość Android/iOS
Wysoki90 Hz11.1 msOnePlus, Pixel 6+
Flagowy120 Hz8.3 msiPhone Pro, Galaxy S22+
Gamingowy144 Hz6.9 msROG Phone, Nubia RedMagic

Narzędzia pomiaru Frame Rate

Do pomiaru Frame Rate w aplikacjach mobilnych dostępne są zarówno wbudowane narzędzia platform, jak i zewnętrzne profilery. W Androidzie głównym narzędziem jest GPU Profiling (Developer Options → Profile GPU Rendering), które pokazuje oś czasu każdej klatki z podziałem na etapy (Draw, Prepare, Process, Execute). Bardziej szczegółową analizę zapewnia Android Studio Profiler — rejestruje on pełny profil renderowania ze wskazaniem konkretnych View powodujących przerysowanie. W iOS używa się Instruments z szablonem Core Animation — pokazuje on FPS, czas renderowania warstw i liczbę renderowań poza ekranem.

Do monitorowania Frame Rate w produkcji stosuje się Firebase Performance (Android) — zbiera on Frame Rate w tle i agreguje według urządzeń, wersji systemu operacyjnego i sesji. W iOS MetricKit dostarcza podobne dane przez MXAnimatoryMetric. Dla gier i aplikacji Flutter używa się FrameTimingCallback (Flutter) i Unity Profiler. Ważne jest mierzenie nie średniego Frame Rate, ale percentyli: P50, P90 i P99. Aplikacja może pokazywać średnie 55 fps, ale mieć P99 = 30 fps — oznacza to, że 1% czasu użytkownicy widzą silne zacięcia, co wystarcza do negatywnych opinii.

Pomiar Frame Rate we Flutter

Przykład w Dart pokazuje, jak zasubskrybować FrameTimingCallback we Flutter i logować liczbę pominiętych klatek. Callback wywoływany jest po każdej zakończonej klatce.

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}");
    }
}

Optymalizacja częstotliwości klatek

Optymalizacja Frame Rate zaczyna się od identyfikacji wąskich gardeł w potoku renderowania. Na etapie Layout główne problemy to nadmierne zagnieżdżenie hierarchii View, używanie względnych Layoutów (RelativeLayout z dużą liczbą reguł) i częste wywołania requestLayout. Rozwiązanie — używanie ConstraintLayout lub płaskiej hierarchii, unikanie zagnieżdżenia powyżej 5–6 poziomów. Na etapie Draw — przerysowanie (overdraw): gdy piksel jest rysowany kilka razy na klatkę. Na przykład białe tło Activity pod półprzezroczystym fragmentem, pod którym jest kolejna warstwa — każdy piksel rysowany jest trzykrotnie. Narzędzie Debug GPU Overdraw pokazuje problematyczne strefy za pomocą oznaczeń kolorystycznych. Zaleca się utrzymywanie overdraw na poziomie 2x lub niżej.

W iOS główne problemy to ciężkie cornerRadius i masksToBounds — powodują one renderowanie poza ekranem (offscreen rendering), przy którym Core Animation tworzy tymczasowy bufor, rysuje w nim, a następnie kopiuje wynik na ekran. Offscreen rendering łatwo zauważyć w Instruments Core Animation: jeśli linia Renderer jest czerwona — występują problemy. Rozwiązanie — używanie UIImageView z wcześniej przyciętymi obrazami zamiast cornerRadius, unikanie groupOpacity i shouldRasterize bez konieczności. Dla obu platform kluczowe jest minimalizowanie liczby wywołań invalidate() i setNeedsDisplay() — każde takie wywołanie uruchamia pełny cykl przerysowania widoku.

Optymalizacja hierarchii w Androidzie

Kod demonstruje zastąpienie głębokiego zagnieżdżenia RelativeLayout płaską strukturą ConstraintLayout. Zmniejszenie poziomu zagnieżdżenia z 4 do 1 skraca czas Layout o 30–50%.

kotlin
// Przykład: płaska struktura przez 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
        // wiązanie danych bez przerysowywania całego kontenera
    }
}

Częstotliwości adaptacyjne i Dynamic Frame Rate

Nowoczesne aplikacje mobilne coraz częściej wykorzystują adaptacyjny Frame Rate — system, który dynamicznie dostosowuje docelową częstotliwość do bieżącego scenariusza. Podczas szybkiego przewijania lista wymaga 120 fps dla płynności, przy statycznym ekranie wystarczy 60 fps lub nawet 30 fps dla wideo. W Androidzie adaptacja realizowana jest przez Choreographer.setFrameInterval (API 33+) i Window.setFrameRate. Deweloper może wskazać systemowi preferowaną częstotliwość: setPreferredRefreshRate w SurfaceView lub setFrameRate w Window. iOS automatycznie zarządza częstotliwością przez ProMotion, ale deweloper może jawnie ustawiać preferredFramesPerSecond dla CADisplayLink.

Dynamiczny Frame Rate jest szczególnie ważny dla gier i aplikacji z animacjami. Według danych Google, obniżenie Frame Rate ze 120 do 60 Hz na statycznym ekranie oszczędza do 30–40% energii GPU. Aby osiągnąć najlepszą równowagę między płynnością a zużyciem energii, zaleca się: mierzyć rzeczywisty Frame Rate w różnych scenariuszach, ustawiać docelowy fps w zależności od sceny (gra — 60, menu — 30, wideo — 24) i przełączać tryby przez komponenty świadome cyklu życia, aby po zminimalizowaniu aplikacja nie marnowała zasobów na renderowanie 120 fps w tle.

Ustawienie preferowanego Frame Rate

Kod w Swift ustawia preferredFramesPerSecond dla CADisplayLink w iOS. Podczas przewijania częstotliwość wzrasta do 120 Hz, po zatrzymaniu — spada do 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() {
        // aktualizacja animacji
    }
}

Często zadawane pytania

Jaki Frame Rate uważa się za dobry dla aplikacji mobilnej?

Dla aplikacji mobilnych docelowy Frame Rate to 60 fps (16.6 ms na klatkę). Dla urządzeń z wyświetlaczami 120 Hz pożądane jest 120 fps. Wartości poniżej 30 fps zauważalnie pogarszają doświadczenie użytkownika.

Czym różni się Frame Rate od częstotliwości odświeżania wyświetlacza?

Frame Rate — ile klatek na sekundę renderuje aplikacja. Refresh Rate — ile razy na sekundę wyświetlacz fizycznie odświeża obraz. Gdy Frame Rate jest niższy niż Refresh Rate, wyświetlacz powiela ostatnią klatkę.

Jak zmierzyć Frame Rate w Androidzie?

Użyj GPU Profiling w Developer Options, Android Studio Profiler lub Firebase Performance. Do programowego pomiaru — Choreographer.FrameCallback z obliczaniem interwału między klatkami.

Czym jest overdraw i jak wpływa na Frame Rate?

Overdraw — przerysowanie jednego piksela kilka razy na klatkę. Każda dodatkowa warstwa zwiększa czas fazy Draw i obniża Frame Rate. Optymalny overdraw to 2x, krytyczny — 4x i więcej.

Jak dynamiczny Frame Rate oszczędza baterię?

Przy statycznej treści Dynamic Frame Rate obniża częstotliwość do 30–60 Hz, zmniejszając obciążenie GPU o 30–40%. Podczas przewijania częstotliwość wzrasta do 90–120 Hz dla płynności.

Podsumowanie

  • Frame Rate — liczba klatek na sekundę, określająca płynność UI i animacji.
  • Docelowy Frame Rate — 60 fps (16.6 ms na klatkę) dla standardowych wyświetlaczy, 120 fps (8.3 ms) dla High Refresh Rate.
  • Pominięte klatki powodują Jank — widoczne zacięcia pogarszające doświadczenie użytkownika.
  • Główne przyczyny niskiego Frame Rate — nadmierne zagnieżdżenie View, overdraw i renderowanie poza ekranem.
  • Choreographer (Android) i CADisplayLink (iOS) synchronizują renderowanie z VSync.
  • Adaptacyjny Frame Rate równoważy płynność i zużycie energii, zmniejszając obciążenie GPU nawet o 40%.
  • Profilowanie Frame Rate — pierwszy krok do optymalizacji wydajności aplikacji mobilnej.

Opracujemy aplikację mobilną pod klucz

IT Sectr tworzy aplikacje na iOS i Androida dla startupów i firm od 2017 roku. Doradzimy Ci i zaproponujemy najlepsze rozwiązanie.

Omów projekt

Przeczytaj również