FPS у мобилним апликацијама: суштина, израчунавање и оптимизација

Аутор: IT Sectr Објављено: 2026-04-01 Време читања: 11 мин

FPS (Frames Per Second) — је метрика која показује колико појединачних кадрова графички систем рендерује у једној секунди. У мобилном развоју, FPS је стандардни показатељ перформанси UI-ја: што је FPS већи, то су анимације глађе и интерфејс одзивнији. Према подацима Google Android Performance, 2025, циљна вредност FPS за мобилне апликације износи 60 кадрова у секунди — то је праг на којем људско око перципира покрет као непрекидан и гладак.

Главно

  • FPS — број кадрова у секунди, основна метрика глаткоће UI-ја.
  • Циљна вредност — 60 FPS, време по кадру — 16.6 мс.
  • За High Refresh Rate дисплеје потребно 120 FPS (8.3 мс по кадру).
  • Пад FPS-а испод 30 видљив је голим оком као запињање и заостајање.
  • Праћење FPS-а у продукцији помаже у откривању регресија перформанси.

Шта је FPS

FPS (Frames Per Second) — је јединица мере фреквенције кадрова која се користи у рачунарској графици, видеу и мобилним интерфејсима. Сваки кадар је статична слика која се приказује на екрану током кратког временског периода. При брзој смени кадрова, мозак их перципира као непрекидан покрет — овај ефекат се назива перзистенција вида. За мобилне апликације, FPS је критична метрика, јер сваки пропуштени кадар (drop) претвара глатку анимацију у приметно запињање. Апликација мора да успе да рендерује сваки кадар строго у оквиру временског буџета: 16.6 мс за 60 FPS, 11.1 мс за 90 FPS, 8.3 мс за 120 FPS.

FPS се мери не само за UI, већ и за игре, видео и камеру. У играма, FPS зависи од сложености сцене, квалитета текстура и снаге GPU-ја. У видеу, FPS је фиксан (24, 30, 60 кадрова/с) и одређен је садржајем. У мобилним апликацијама, FPS зависи од ефикасности UI кода: сложености Layout-а, броја View-ова, учесталости прецртавања и рада GC (Garbage Collection). Према Apple WWDC 2022, просечан FPS у апликацији може да падне за 10–15% због неефикасног ажурирања колекција (reloadData уместо insert/delete/dequeueReusableCell). Мерење FPS-а у реалном времену је стандардна пракса за QA инжењере и програмере који раде на перформансама.

Како се израчунава FPS

Израчунавање FPS у мобилној апликацији заснива се на мерењу времена између узастопних кадрова. Најједноставнија формула: FPS = 1000 / deltaTimeMs, где је deltaTimeMs интервал између завршетка претходног кадра и завршетка тренутног. Ако је тренутни кадар рендерован за 20 мс, FPS = 1000 / 20 = 50. Међутим, у пракси FPS ретко када буде стабилан чак ни у једној секунди: типичан профил укључује кадрове од 12–16 мс, испреплетане са пропуштеним (jank) или спорим кадровима (40–60 мс). Због тога се FPS мери као покретни просек за 1–5 секунди или као перцентили дистрибуције времена кадрова.

У Android-у, FPS се израчунава путем Choreographer, који добија колбек од VSync-а (импулса синхронизације дисплеја). Сваки колбек одговара једном кадру. Ако колбек није стигао — кадар је пропуштен. Choreographer омогућава мерење тачног броја кадрова у секунди и броја пропуштених (skipped frames). У iOS-у, CADisplayLink ради аналогно — позива се сваки пут када је дисплеј спреман за рендеровање новог кадра. Својство timestamp садржи тачно време последњег кадра, а targetTimestamp — очекивано време следећег. Разлика између њих је буџет времена за тренутни кадар.

Праћење FPS-а путем CADisplayLink-а

Код у Swift-у демонстрира једноставно праћење FPS-а путем CADisplayLink. Бројач frameCount се повећава при сваком позиву и једном у секунди се израчунава стварни FPS.

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

Зашто је 60 FPS стандард

Стандард 60 FPS (60 Hz) учврстио се у индустрији из неколико разлога. Први — физиолошки: људско око не разликује појединачне кадрове при фреквенцији изнад 50–60 Hz, перципирајући их као гладак покрет. Овај праг се назива Critical Flicker Fusion (CFF). Други — историјски: прве катодне цеви (CRT) радиле су на 60 Hz у САД (NTSC) и 50 Hz у Европи (PAL). Модерни LCD дисплеји наследили су ову фреквенцију. Трећи — инжењерски: за UI анимације, 60 FPS обезбеђује суб-милисекундно кашњење одговора на додир, што је критично за унос текста, скроловање и превлачење.

За мобилне програмере, 60 FPS није само препорука, већ строги буџет од 16.6 мс по кадру. Овај буџет дели се између свих фаза рендеровања: Input (1–2 мс), Animation (2–3 мс), Layout (3–5 мс), Draw (3–5 мс) и Swap (1–2 мс). Ако нека фаза премаши свој под-буџет, кадар можда неће стати у 16.6 мс. Google Android Performance препоручује да се уложи 12–14 мс на припрему кадра, остављајући 2–4 мс резерве за системске прекиде (GC, позадинске нити). Према Firebase Performance, апликације са просечним FPS-ом испод 52 и P99 FPS испод 30 добијају 35% више жалби на перформансе у Google Play рецензијама.

FPS и Frame Time:веза

FPS и Frame Time (време кадра) — две су стране исте метрике и важно их је не мешати. FPS је брзина, Frame Time је кашњење. При 60 FPS, сваки кадар траје 16.6 мс. При 30 FPS — 33.3 мс. Али FPS је нелинеарна метрика: пад са 60 на 30 FPS значи да је време кадра порасло 2 пута, а пад са 30 на 20 — 1.5 пута. Због тога профилисачи приказују не FPS, већ Frame Time — то омогућава увид у проблематичне кадрове, а не у просечну фреквенцију. На пример, просек 55 FPS може да прикрије да 5% кадрова има Frame Time 50–100 мс — ови кадрови изазивају Jank, али не утичу много на просечан FPS.

При анализи перформанси препоручује се гледати не просечан FPS, већ хистограм Frame Time-а. У Android Studio Profiler и iOS Instruments, Frame Time је приказан као скала, где је зелена зона — до 16.6 мс (60 FPS), жута — 16.6–33.3 мс (30–60 FPS), црвена — преко 33.3 мс (испод 30 FPS). Свака црвена колона је приметно кашњење за корисника. Практично правило: P95 Frame Time (95% кадрова стаје у X мс) — поузданија је метрика од просечног FPS-а. Ако P95 Frame Time премашује 32 мс (30 FPS), апликација се доживљава као спора чак и при просечном FPS = 50.

Конверзија Frame Time у FPS

Функција у Kotlin-у за конверзију низа времена кадрова у FPS са перцентилима. Враћа не само просечан FPS, већ и P50, P90 и P99 за детаљну анализу.

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 и нови дисплеји

Модерни мобилни уређаји са дисплејима од 90, 120 и 144 Hz постављају нове захтеве за FPS. Ако апликација даје 60 FPS на 120-херцном дисплеју, корисник види микро-запињање, јер сваки други циклус освежавања екрана добија исти кадар. За одржавање 120 FPS, буџет по кадру се смањује са 16.6 на 8.3 мс — ово захтева двоструко ефикаснији код рендеровања. Према програмерима Android-а (Google I/O 2023), за постизање стабилних 120 FPS потребно је: избегавати алокације у Draw петљи, минимизирати број View-ова у хијерархији (мање од 80), одустати од тешких drawable у корист VectorDrawable-а и користити surfaceView за сложену графику.

У iOS-у ситуација је аналогна: iPhone Pro са ProMotion (120 Hz) захтева двоструко више кадрова, али време за сваки кадар је упола краће. Apple напомиње да не морају све анимације да раде на 120 FPS — Core Animation аутоматски смањује фреквенцију за непокретне или споро променљиве елементе. Међутим, скроловање, анимације гестова и транзиције морају да дају 120 FPS за осећај "свиленкастости". Главни проблеми при преласку са 60 на 120 FPS: повећање потрошње енергије (за 25–40% за GPU), загревање уређаја и тротлинг — када фреквенција опада због прегревања. Препоручује се имплементација fallback механизма: ако Frame Time стабилно премашује 8.3 мс, програмски смањити циљну фреквенцију на 60 FPS, уместо чекања системског тротлинга.

Прекидач између 60 и 120 FPS

Код у Java за Android одређује да ли уређај може да подржи 120 FPS и пребацује режим рендеровања. Користи Display.getMode за одређивање подржаних фреквенција.

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

Оптимизација FPS-а у апликацијама

Оптимизација FPS захтева систематски приступ, почев од профилисања и завршавајући рефакторисањем проблематичних места. Прва фаза — измерити тренутни FPS помоћу профилисача (. Друга фаза — пронаћи кадрове који премашују буџет. За Android, ово се може урадити путем GPU Profiling или Perfetto. За iOS — Instruments са шаблоном Core Animation. Трећа фаза — отклонити узроке: смањити overdraw, смањити дубину угнежђења View-ова, заменити Layout фазу са ConstraintLayout, додати ViewHolder Recycling, преместити тешка израчунавања у позадинску нит.

Специфичне за FPS оптимизације укључују: Frame Pacing — механизам који равномерно распоређује време између кадрова како би се избегли "пакети" брзих и спорих кадрова. У Android-у, Choreographer.FrameCallback са фиксним интервалом омогућава имплементацију Frame Pacing-а. У iOS-у, CADisplayLink.preferredFrameRateRange чини исто. Други механизам — Triple Buffering: систем користи три бафера уместо два, што омогућава GPU-у да почне цртање следећег кадра без чекања на ослобађање претходног. Android аутоматски укључује Triple Buffering када је потребно, али у iOS-у програмер може експлицитно да га затражи путем CAMetalLayer. Трећи — Texture Caching: кеширање битмапа у GPU меморији како се не би поново учитавале при сваком кадру.

Frame Pacing путем Choreographer-а

Пример у Kotlin-у демонстрира имплементацију Frame Pacing са фиксним интервалом од 16.6 мс. Сви колбекови стижу са равномерним интервалом, чак и ако систем касни.

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) {
        // рендеровање кадра
    }
}

Често постављана питања

Који FPS се сматра удобним за корисника?

60 FPS — удобан ниво за мобилне апликације. Разлика између 60 и 120 FPS приметна је само на дисплејима са високом фреквенцијом освежавања код брзих анимација (скроловање, превлачење). Испод 30 FPS — неугодност.

Како је FPS повезан са временом кадра?

FPS = 1000 / FrameTime (ms). Ако је Frame Time = 16.6 мс, FPS = 60. Ако је Frame Time = 33.3 мс, FPS = 30. Препоручује се праћење Frame Time-а, а не FPS-а, јер он показује проблематичне кадрове.

Зашто FPS опада при скроловању?

При скроловању, систем позива Layout и Draw за сваки нови елемент листе. Ако су View-ови сложени, Layout се не кешира или користе тешки drawable — Frame Time расте и FPS опада. Решење — ViewHolder recycling и равна хијерархија.

Како измерити FPS у iOS-у?

Користите Instruments са шаблоном Core Animation (приказује FPS у реалном времену). За програмско мерење — CADisplayLink са бројањем кадрова у секунди. За продукцију — MetricKit са метриком MXAnimatoryMetric.

Шта је Triple Buffering и како утиче на FPS?

Triple Buffering користи три бафера уместо два, омогућавајући GPU-у да започне рендеровање следећег кадра пре завршетка VSync-а тренутног. Ово изглађује вршна оптерећења и повећава стабилност FPS-а, али додаје 1 кадар кашњења.

Закључак

  • FPS — кључна метрика глаткоће интерфејса, циљна вредност — 60 кадрова у секунди.
  • Frame Time (време кадра) — прецизнији показатељ од FPS-а, посебно P95 и P99 перцентили.
  • За 120 Hz дисплеје потребно је 120 FPS са буџетом од 8.3 мс по кадру.
  • Главни узроци пада FPS-а — overdraw, дубоко угнежђење View-ова, алокације у Draw петљи.
  • Frame Pacing и Triple Buffering помажу у изглађивању неравномерности времена кадрова.
  • Профилисање FPS-а — путем GPU Profiling (Android), Instruments Core Animation (iOS), Firebase Performance.
  • Праћење P95 Frame Time-а у продукцији критично је за откривање регресија пре масовних жалби корисника.

Развићемо мобилну апликацију под кључ

IT Sectr креира iOS и Android апликације за стартапе и предузећа од 2017. године. Саветоваћемо вас и предложити најбоље решење.

Разговарајте о пројекту

Прочитајте такође