ANR (Application Not Responding) — це системне сповіщення Android, яке з'являється, коли додаток не реагує на введення протягом 5 секунд. На відміну від глюків (логічні помилки без блокування UI) та лагів (уповільнення без повної зупинки), ANR — це критична несправність, яку фіксує операційна система: Android відображає діалог «Додаток не відповідає» з пропозицією закрити або зачекати. Згідно з Android Vitals Documentation, додатки з ANR rate вище 0.5% мають понижений рейтинг в Google Play і можуть бути приховані від рекомендацій. Діагностика включає аналіз /data/anr/traces.txt, використання StrictMode та профілювання головного потоку.
Головне
ANR (Application Not Responding) — це механізм захисту користувача в Android, який спрацьовує, коли додаток перестає реагувати на введення. Система відстежує час обробки подій: якщо BroadcastReceiver не завершує onReceive за 10 секунд, Service не повертається з onCreate за 20 секунд, а ContentProvider не відповідає за 15 секунд — Android генерує ANR.
Коли виникає ANR, Android показує системний діалог поверх усіх вікон: «Додаток не відповідає. Закрити його чи зачекати?» Користувач може закрити додаток або дочекатися його відновлення. Якщо ANR повторюються часто, користувач видаляє додаток. Google Play враховує ANR rate — відсоток сесій з ANR — в алгоритмах ранжування.
На iOS немає аналогу ANR з системним діалогом. Натомість Apple використовує Watchdog, який завершує процес з кодом 0x8badf00d. Користувач не бачить діалог — додаток просто закривається на головний екран. Це робить ANR на Android більш помітним для користувача, але дає системі більше інформації для діагностики.
ANR виникає, коли система відстежує таймаут для одного з чотирьох типів компонентів. Кожен компонент має свій ліміт часу.
BroadcastReceiver виконується в головному потоці. Якщо onReceive запускає синхронний мережевий запит, довгий запис в БД або очікує блокування — через 10 секунд виникає ANR. Рішення: використовуйте goAsync() та WorkManager для фонового опрацювання. Типовий сценарій — отримання Push-сповіщення від FCM та синхронне збереження в Room.
Service.onCreate та Service.onStartCommand мають ліміт 20 секунд. Якщо сервіс запускає важку ініціалізацію (завантаження бібліотек, читання конфігурації з мережі) в головному потоці — ANR неминучий. Використовуйте IntentService (застарілий) або WorkManager для гарантованого виконання в фоновому потоці.
ContentProvider.onCreate виконується до Application.onCreate та має ліміт 15 секунд. Якщо провайдер виконує міграцію БД, завантажує словники або ініціалізує SDK з мережі — це викликає ANR при запуску додатка. Рішення: lazy-ініціалізація, винесення важких операцій в WorkManager.
Android надає кілька інструментів для аналізу ANR: від системних логів до спеціалізованих бібліотек.
При кожному ANR Android зберігає файл /data/anr/traces.txt з дампом стеків усіх потоків додатка. Знайдіть потік «main» — останній метод у стеку вказує на причину. Типові патерни: Thread.sleep(), InputStream.read(), BinderProxy.transact(). Для вилучення файлу з пристрою використовуйте adb з правами суперкористувача.
Firebase Crashlytics автоматично збирає ANR та показує їх на панелі разом з трасуванням. Для Android 11+ звіти ANR надходять з повним стеком головного потоку. Інтеграція потребує додавання залежності та ініціалізації FirebaseApp в Application.onCreate.
CPU Profiler в Android Studio дозволяє записати трасування роботи додатка та побачити, які методи займають час процесора. Увімкніть «Record with method traces» та відтворіть сценарій, що викликає ANR. На часовій шкалі буде видно, які методи виконувалися в main thread в момент зависання.
Приклад інтеграції Firebase Crashlytics для збору ANR на Android:
class App : Application() {
override fun onCreate() {
super.onCreate()
FirebaseApp.initializeApp(this)
FirebaseCrashlytics.getInstance()
.setCrashlyticsCollectionEnabled(true)
StrictMode.setThreadPolicy(StrictMode.ThreadPolicy.Builder()
.detectAll()
.penaltyLog()
.build())
}
}
Усунення ANR — це насамперед перенесення всіх довгих операцій з головного потоку в фонові. Розглянемо конкретні техніки для кожного типу компонента.
WorkManager — рекомендоване Google рішення для фонової роботи. Він гарантує виконання завдання в фоновому потоці з урахуванням стану пристрою. На відміну Service, WorkManager не блокує головний потік та стійкий до перезапуску додатка. Для BroadcastReceiver використовуйте goAsync() та передайте PendingResult в WorkManager.
Запускайте всі мережеві запити, роботу з БД та файлові операції з Dispatchers.IO. Головний потік повинен тільки оновлювати UI. Використовуйте viewModelScope для автоматичного скасування корутин при знищенні Activity. Уникайте runBlocking() в будь-якому контексті — це синхронне блокування поточного потоку.
Якщо ContentProvider виконує довгу ініціалізацію, використовуйте механізм відстроченого завантаження: створіть провайдер, який повертає дані одразу, а важку ініціалізацію запустіть через WorkManager з затримкою. Це запобігає ANR при запуску додатка, коли система найбільш чутлива до затримок.
Приклад правильного використання BroadcastReceiver з goAsync в Android:
class FcmReceiver : BroadcastReceiver() {
override fun onReceive(context: Context?, intent: Intent?) {
val pendingResult = goAsync()
WorkManager.getInstance(context!!)
.enqueue(OneTimeWorkRequest.from(NotificationWorker::class.java))
pendingResult.finish()
}
}
Найкращий спосіб боротьби з ANR — попередити їх появу на етапі розробки через інструменти та архітектурні рішення.
StrictMode зі вмкненими політиками detectNetwork() та detectDiskReads()/detectDiskWrites() виявляє потенційні ANR на етапі розробки. В Debug-збірці встановіть penaltyDeath — будь-яке порушення призведе до негайного падіння, і розробник побачить проблему до коміту.
Firebase Performance відстежує час виконання ключових операцій та показує, які сценарії перевищують поріг ANR. Налаштуйте кастомні трейси для кожного екрану та мережевого запиту. Якщо час виконання перевищує 3 секунди — це потенційний ANR, що потребує оптимізації.
Симулюйте повільні умови: обмежте швидкість мережі через Network Link Conditioner на iOS або Android Emulator. Уповільніть читання з диска через емуляцію повільної пам’яті. ANR часто проявляються саме в таких умовах, на швидких пристроях розробника вони не помітні.
Часто задавані питання
Android явно відстежує час обробки подій на головному потоці та показує діалог ANR. iOS використовує Watchdog, який примусово закриває додаток при зависанні понад 10–20 секунд. ANR — особливість архітектури Android, де кілька компонентів (BroadcastReceiver, Service) мають жорсткі таймаути.
На Android 11+ можна отримати ANR-дамп через adb shell dumpsys dropbox --print data_app_anr. На Android 10 та нижче без root доступу до /data/anr/traces.txt немає. Використовуйте Firebase Crashlytics — він збирає звіти ANR автоматично для Android 11+.
Google Play рекомендує ANR rate менше 0.5% — тобто не більше 5 ANR на 1000 сесій. Додаток з rate вище 1% отримує попередження в Google Play Console та може бути прихований з рекомендацій. В ідеалі ANR rate повинен бути нижче 0.1%.
Корутина сама по собі не блокує потік. Але якщо всередині корутини виконується runBlocking на головному потоці або корутина запущена з Dispatchers.Main та виконує довгу CPU-операцію — це викличе ANR. Використовуйте Dispatchers.IO для введення-виведення та Dispatchers.Default для обчислень.
Використовуйте Android Emulator з профілем «Slow Network» або напишіть тест, що викликає Thread.sleep(6000) на головному потоці. Запустіть додаток через Debug і через 5 секунд ви побачите ANR-діалог. Перевірте, що в logcat з'явився запис про ANR з трасуванням.
Підсумки
Ми розробимо мобільний застосунок під ключ
IT Sectr створює застосунки для iOS та Android для стартапів і бізнесу з 2017 року. Ми проконсультуємо вас і запропонуємо найкраще рішення.
Читайте також