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 года. Мы проконсультируем вас и предложим наилучшее решение.
Читайте также