Лаги в мобільній розробці: причини та методи усунення

Автор: IT Sectr Опубліковано: 2026-07-28 Час читання: 9 хв

Лаг у мобільному додатку — це помітна затримка між дією користувача та реакцією інтерфейсу, яка виникає через перевантаженість головного потоку, витоків пам'яті або неоптимальних операцій введення-виведення. На відміну від глюків, пов'язаних з логічними помилками, лаг — це проблема продуктивності: додаток працює коректно, але повільно. За даними AppDynamics Mobile App Performance Report 2024, 62% користувачів видаляють додаток, якщо він гальмує більше 3 секунд. Діагностика лагів потребує профілювання CPU, пам'яті та мережі за допомогою Android Studio Profiler та Xcode Instruments.

Головне

  • Лаг — помітна затримка інтерфейсу при коректній роботі додатку, викликана проблемами продуктивності
  • Основні причини — блокування головного потоку, витоки пам'яті, часті GC паузи, неоптимальні SQL-запити та мережеві виклики
  • Діагностика виконується через CPU Profiler, Memory Profiler та Network Profiler в Android Studio та Time Profiler в Xcode
  • Усунення включає вивантаження завдань у фонові потоки, впровадження кешування, оптимізацію адаптерів та lazy-завантаження даних
  • Профілактика — StrictMode, Main Thread Checker, асинхронні черги GCD та Kotlin Coroutines з правильними диспетчерами

Що таке лаг у мобільній розробці

Лаг у мобільному додатку — це суб'єктивно відчутна затримка між дією користувача (дотик, свайп, введення тексту) та реакцією інтерфейсу. Технічно лаг вимірюється як час між подією введення та повним рендером кадру: комфортний поріг — до 100 мс, помітний — від 200 мс, критичний — понад 500 мс.

Відмінність лагу від глюка та гальмування

У користувацькій термінології «лагає» і «гальмує» часто використовуються як синоніми, але технічно лаг — це фіксована затримка (наприклад, 300 мс при кожному натисканні), а «гальмує» — непостійне уповільнення: додаток то працює плавно, то зависає на секунду. Глюк, на відміну від лагу, пов'язаний не зі швидкістю, а з коректністю відображення.

Вплив лагів на метрики додатку

Google Play та App Store враховують показники продуктивності при ранжуванні додатків. ANR rate, частота джиттера (jank) та час запуску впливають на видимість у пошуку та конверсію встановлень. Додаток з постійними лагами втрачає до 40% користувачів після першого запуску.

Причини лагів та гальмування в додатках

Лаги виникають, коли головний потік UI не встигає обробити кадри з частотою 60 FPS (16.6 мс на кадр) або 120 FPS (8.3 мс). Розглянемо основні джерела затримок.

Блокування головного потоку

Будь-яка синхронна операція в UI-потоці — читання з SharedPreferences, робота з базою даних через Room без suspend, декодування зображення в Bitmap — блокує відтворення кадру. На Android це призводить до пропуску кадрів (jank), на iOS — до затримки рендеру Core Animation.

Витоки пам'яті та часті GC паузи

Коли збирач сміття (Garbage Collector) на Android або ARC на iOS виконує звільнення пам'яті, всі потоки призупиняються. Часті GC паузи виникають при створенні великої кількості тимчасових об'єктів — наприклад, при кожному виклику адаптера списку створюється новий екземпляр ViewHolder. Це проявляється як сіпане прокручування.

Важкі layout-ієрархії

Вкладені ConstraintLayout, множинні LinearLayout, перекриті View — кожна вкладеність збільшує час на measure та layout pass. Xcode вказує, що глибока ієрархія шарів (більше 10 рівнів) викликає падіння FPS на 20-30%.

  • Android — надмірні requestLayout, неефективні ConstraintLayout ланцюги, великий Bitmap без downscale
  • iOS — Auto Layout обмеження з конфліктами, важкі CALayer, shadowPath без rasterization
  • Крос-платформа — синхронні HTTP-виклики в UI-потоці, важкі JSON-парсинги, неоптимальні зображення високої роздільної здатності

Як діагностувати затримки продуктивності

Для виявлення причин лагів використовуються профілювальники, вбудовані в IDE, та інструменти системного моніторингу. Кожен інструмент вирішує своє завдання.

CPU Profiler в Android Studio

CPU Profiler показує, які методи займають процесорний час та в яких потоках вони виконуються. Якщо метод з важкими обчисленнями виконується в main thread — це корінь проблеми. Запис трасування з увімкненим sample Java Method дозволяє побачити стек викликів у кожен момент часу та знайти «гарячі точки».

Time Profiler в Xcode Instruments

Аналогічний інструмент для iOS — Time Profiler — збирає вибірки стеку кожну мілісекунду та показує, який відсоток часу CPU зайнятий кожним методом. Комбінація з прапорцем Main Thread Only фільтрує лише операції на головному потоці, що прямо вказує на джерела лагів.

Network Profiler та аналіз запитів

Повільні мережеві запити створюють враження лагів, навіть якщо UI-потік не заблокований. Network Profiler в Android Studio та Network Link Conditioner в Xcode дозволяють симулювати повільне з'єднання та виявити, як додаток поводиться в реальних умовах. Chunked-відповіді без прогресу та великі JSON-пейлоади — типові джерела уявних лагів.

Приклад профілювання мережевого запиту з OkHttp з виміром часу:

kotlin
class TimingInterceptor : Interceptor {
    override fun intercept(chain: Interceptor.Chain): Response {
        val start = System.nanoTime()
        val response = chain.proceed(chain.request())
        val duration = (System.nanoTime() - start) / 1_000_000
        Log.d("Timing", "Request took $duration ms")
        return response
    }
}

Методи усунення лагів на Android та iOS

Усунення лагів потребує системної роботи: від оптимізації одного методу до архітектурних змін. Розглянемо найбільш ефективні техніки.

Асинхронна обробка через корутини та GCD

Kotlin Coroutines з диспетчером Dispatchers.IO для мережевих запитів та Dispatchers.Default для обчислень гарантують, що головний потік залишається вільним для UI. На iOS Grand Central Dispatch з queue .global(qos: .userInitiated) для фонових завдань та .main для оновлення UI — стандартний підхід. Уникайте sync-операцій між чергами.

Оптимізація адаптерів та списків

RecyclerView на Android та UICollectionView на iOS потребують правильного налаштування: ViewHolder з мінімальним створенням об'єктів в onBindViewHolder, DiffUtil для обчислення змін, prefetching для завантаження даних заздалегідь. На iOS використовуйте diffable data source для анімованих оновлень без ручного керування.

Кешування даних та зображень

Завантаження одного й того ж зображення при кожному прокручуванні — гарантований лаг. Coil (Android) та Kingfisher (iOS) кешують зображення в пам'яті та на диску, забезпечуючи миттєве відображення при повторному запиті. Для даних використовуйте Room з кешуючим шаром на основі Flow або Combine.

Приклад налаштування кешування зображень з Coil на Android:

kotlin
val imageLoader = ImageLoader(context) {
    memoryCachePolicy(CachePolicy.ENABLED)
    diskCachePolicy(CachePolicy.ENABLED)
    crossfade(true)
    size(512, 512)
}

// Loading with auto-caching enabled
imageView.load("https://example.com/image.jpg") {
    placeholder(R.drawable.placeholder)
    error(R.drawable.error)
}

Профілактика лагів на етапі розробки

Запобігти лагам дешевше, ніж виправляти їх у продакшні. Профілактичні заходи вбудовуються в процес розробки на рівні інструментів та архітектури.

StrictMode на Android

StrictMode — вбудований інструмент Android, який виявляє випадкові операції введення-виведення та мережеві виклики на головному потоці на етапі розробки. Увімкніть його в Application.onCreate з політикою penaltyDeath для критичних порушень. Це єдиний спосіб гарантувати, що розробник побачить проблему до коміту.

Main Thread Checker на iOS

Аналог для iOS — Main Thread Checker в Xcode, що входить до Runtime Sanitization — автоматично перевіряє, що всі виклики UIKit та AppKit виконуються з головного потоку. Увімкніть його в схемі збірки Debug та досягніть нульових попереджень в CI.

Бенчмарки продуктивності в CI

Додайте в CI-пайплайн прогін Macrobenchmark (Android) та XCTMetrics (iOS) для вимірювання часу запуску, FPS прокручування та використання пам'яті. Встановіть пороги: якщо новий коміт збільшує час запуску більш ніж на 5% — збірка падає.

  • Android — Macrobenchmark, Baseline Profiles, Jetpack Benchmark Library
  • iOS — XCTMetrics, os_signpost, MetricKit для збору метрик з пристроїв користувачів
  • Загальний підхід — профілювання до та після кожної значущої зміни, регресійні тести продуктивності

Часті запитання

Чим лаг відрізняється від низького FPS?

Лаг — це суб'єктивне відчуття затримки, яке може виникати і при високому FPS, якщо затримка викликана часом обробки введення, а не рендеру. Низький FPS (менше 30 кадрів/с) — одна з причин лагів, але не єдина.

Як виміряти лаг у додатку?

Використовуйте Frame Timing API на Android (Choreographer) та CADisplayLink на iOS для вимірювання часу між кадрами. Google Play Vitals показує jank rate в реальних умовах. Для точних вимірювань застосовуйте Macrobenchmark зі сценаріями прокручування.

Чому лаги з'являються лише на старих пристроях?

Старі пристрої мають менше ядер CPU, менший об'єм RAM та повільнішу пам'ять. Операція, яка виконується за 5 мс на флагмані, на бюджетному пристрої може зайняти 50 мс. Тестуйте продуктивність на пристроях нижнього сегмента та встановлюйте Baseline Profiles для AOT-компіляції.

Чи може оптимізація зображень усунути лаги?

Так, це один із найефективніших способів. Зображення високої роздільної здатності займають багато пам'яті та CPU часу на декодування. Використовуйте downscale до розміру View, формати WebP (Android) та HEIC (iOS), а також кешування через Coil або Kingfisher.

Як SwiftUI впливає на лаги порівняно з UIKit?

SwiftUI автоматично оптимізує оновлення через diffing, що знижує ризик лагів при зміні даних. Однак складні ієрархії та часті перебудови body можуть викликати падіння FPS. UIKit дає більше контролю над продуктивністю, але потребує ручної оптимізації.

Підсумки

  • Лаг — затримка між дією користувача та реакцією інтерфейсу, викликана проблемами продуктивності, а не логічними помилками
  • Основні причини — блокування головного потоку, витоки пам'яті, важкі layout-ієрархії та неоптимальні мережеві запити
  • Діагностика проводиться через CPU Profiler, Memory Profiler та Network Profiler на Android; Time Profiler та Main Thread Checker на iOS
  • Усунення включає корутини, GCD, оптимізацію адаптерів, кешування зображень та даних і lazy-завантаження
  • Профілактика — StrictMode, Macrobenchmark, Baseline Profiles, MetricKit та регресійні тести продуктивності
  • Вимірювання — Choreographer на Android, CADisplayLink на iOS, Google Play Vitals для продакшн-моніторингу
  • Рекомендація: налаштуйте CI з перевіркою FPS та часу запуску при кожному коміті для запобігання регресіям

Ми розробимо мобільний застосунок під ключ

IT Sectr створює застосунки для iOS та Android для стартапів і бізнесу з 2017 року. Ми проконсультуємо вас і запропонуємо найкраще рішення.

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

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