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 мс.
  • Для дисплеїв з високою частотою оновлення потрібно 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 Гц) закріпився в індустрії з кількох причин. Перша — фізіологічна: людське око не розрізняє окремі кадри при частоті вище 50–60 Гц, сприймаючи їх як плавний рух. Цей поріг називається Critical Flicker Fusion (CFF). Друга — історична: перші електронно-променеві трубки (CRT) працювали на частоті 60 Гц у США (NTSC) і 50 Гц у Європі (PAL). Сучасні ЖК-дисплеї успадкували цю частоту. Третя — інженерна: для 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 і час кадру: взаємозв'язок

FPS і час кадру (Frame Time) — дві сторони однієї метрики, і їх важливо не плутати. FPS — швидкість, час кадру — затримка. При 60 FPS кожен кадр займає 16,6 мс. При 30 FPS — 33,3 мс. Але FPS — нелінійна метрика: падіння з 60 до 30 FPS означає, що час кадру зріс у 2 рази, а падіння з 30 до 20 — у 1,5 рази. Тому профілювальники показують не FPS, а час кадру — це дозволяє бачити проблемні кадри, а не усереднену частоту. Наприклад, середнє 55 FPS може приховувати, що 5% кадрів мають час кадру 50–100 мс — ці кадри викликають Jank, але не сильно впливають на середнє FPS.

При аналізі продуктивності рекомендується дивитися не середній FPS, а гістограму часу кадру. В Android Studio Profiler та iOS Instruments час кадру відображається у вигляді шкали, де зелена зона — до 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.

Конвертація часу кадру в 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 Гц висувають нові вимоги до 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 Гц) потребує вдвічі більше кадрів, але час на кожен кадр вдвічі менший. Apple зазначає, що не всі анімації повинні працювати на 120 FPS — Core Animation автоматично знижує частоту для нерухомих або повільно змінюваних елементів. Однак скрол, анімації жестів і transitions повинні видавати 120 FPS для відчуття «шовковистості». Основні проблеми при переході з 60 на 120 FPS: збільшення енергоспоживання (на 25–40% для GPU), нагрів пристрою та троттлінг — коли частота падає через перегрів. Рекомендується реалізувати fallback-механізм: якщо час кадру стабільно перевищує 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 і flat-ієрархія.

Як виміряти 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 Гц дисплеїв потрібно 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 року. Ми проконсультуємо вас і запропонуємо найкраще рішення.

Обговорити проект

Читайте також