ANR (Application Not Responding) — это системное уведомление Android, которое появляется, когда приложение перестаёт реагировать на пользовательский ввод дольше 5 секунд. По данным Android Developers, основная причина — долгие операции на главном потоке, блокирующие обработку касаний и отрисовку интерфейса. Понимание механизмов ANR необходимо каждому Android-разработчику для создания отзывчивых приложений.
Главное
ANR (Application Not Responding) — это диалоговое окно операционной системы Android, которое появляется, когда приложение перестаёт отвечать на пользовательский ввод. Система отслеживает время обработки событий через InputDispatcher: если прикосновение или нажатие кнопки не обработано за 5 секунд, Android показывает диалог с предложением закрыть или подождать приложение.
Механизм ANR защищает пользовательский опыт от зависших приложений. Android не позволяет одному приложению блокировать всю систему — в отличие от Desktop-ОС, мобильная платформа принудительно ограничивает время обработки событий. BroadcastReceiver имеет лимит 10 секунд, а служба foreground — 20 секунд.
ANR НЕ является исключением в коде — это системный механизм на уровне Linux-процессов. Android отправляет сигнал SIGQUIT процессу, после чего система сохраняет стек вызовов всех потоков в файл traces.txt. Разработчик получает ANR не как catch-исключение, а как отчёт после перезапуска приложения. На Android 11+ появился API ApplicationExitInfo, который позволяет программно получить причину завершения процесса, включая ANR — это упрощает сбор статистики без ручного парсинга traces.txt.
Пять категорий операций стабильно приводят к ANR в Android-приложениях. Каждая из них блокирует главный поток, не давая системе обрабатывать события ввода и перерисовку экрана.
Синхронные HTTP-запросы, выполненные на UI-потоке, — самая частая причина ANR у начинающих разработчиков. Даже быстрый запрос к серверу может занять 1–3 секунды, а при плохом соединении — 30 секунд и больше. Android явно запрещает сетевые операции на главном потоке начиная с API 11, выбрасывая NetworkOnMainThreadException.
Используйте Coroutines или RxJava для асинхронных вызовов. Корутины с диспетчером Dispatchers.IO выполняют запрос в фоновом потоке, а результат передают на главный через Dispatchers.Main. Это полностью исключает блокировку UI-потока сетевыми операциями.
fun fetchUserData() {
CoroutineScope(Dispatchers.Main).launch {
val result = withContext(Dispatchers.IO) {
api.getUserData() // фоновая операция
}
updateUI(result) // результат на главном потоке
}
}
Обработка больших массивов данных, парсинг JSON или XML, работа с bitmap напрямую на главном потоке — вторая по частоте причина ANR. Даже 300 миллисекунд непрерывной работы UI-потока без возврата в цикл событий вызывают заметную задержку отрисовки, а пограничное значение в 5 секунд фиксируется как ANR.
WorkManager и фоновые сервисы предназначены для выноса тяжёлых вычислений из главного потока. Используйте AsyncTask (устарел), ListenableFuture или Kotlin Flow для передачи данных порциями, не блокируя UI.
Deadlock возникает, когда два потока удерживают блокировки и ждут друг друга. Если один из потоков — главный, система фиксирует ANR ровно через 5 секунд. Thread.join(), CountDownLatch.await() и synchronized-блоки, вызываемые с UI-потока, несут риск блокировки.
Избегайте любых блокирующих операций на главном потоке. Вместо synchronized используйте ConcurrentHashMap, вместо Thread.join() — корутины с async/await. Это правило действует для любого языка в Android: Java, Kotlin или C++ через JNI.
BroadcastReceiver выполняется на главном потоке по умолчанию. Если onReceive() занят более 10 секунд, Android показывает ANR. Загрузка данных из БД или сети внутри onReceive — гарантированный путь к зависанию.
Используйте goAsync() внутри BroadcastReceiver для переключения в фоновый поток, либо registerReceiver с getBackgroundBroadcastReceiver(). Это позволяет обрабатывать события без блокировки UI.
Тяжёлые запросы к ContentProvider или прямая работа с SQLite на UI-потоке — менее очевидная, но частая причина ANR. При миграции базы данных или bulk-вставке тысяч записей время выполнения может превысить 5-секундный лимит.
Переносите все операции с базой данных в фоновые потоки через Room с suspend-функциями. Room автоматически проверяет, что запрос не выполняется на главном потоке, и выбрасывает исключение при нарушении.
Диагностика ANR отличается от отладки обычных исключений — вы не можете поймать ANR в try-catch. Основной источник информации — файл traces.txt, который Android создаёт в момент зависания.
traces.txt содержит стек вызовов всех потоков приложения на момент ANR. Чтобы прочитать файл с реального устройства, выполните команду adb bugreport, которая собирает полный отчёт системы, включая все ANR за последнее время. Для эмулятора файл доступен в /data/anr/traces.txt. Стек вызовов показывает, какой метод выполнялся на главном потоке в момент блокировки.
adb bugreport bugreport.zip
unzip -p bugreport.zip "*traces*" > traces.txt
Google Play Console предоставляет раздел ANR & Crash с агрегированными отчётами и частотами ошибок. Для каждого ANR показан стек вызовов и статистика по устройствам: модель, версия Android, регион. Это позволяет выявить ANR, которые зависят от конкретных устройств или версий системы.
Android Studio с 2021 года содержит ANR Watchdog в профилировщике. Он автоматически записывает дамп потоков, если главный поток не отвечает дольше порогового времени. Инструмент показывает временную шкалу событий: какие operations запускались, какие методы выполнялись и на каком этапе произошла блокировка.
Профилактика ANR строится на одном фундаментальном правиле: главный поток должен только обрабатывать события UI. Любая операция дольше 16 миллисекунд (время одного кадра) должна выполняться в фоновом потоке.
StrictMode — встроенный инструмент Android для обнаружения потенциальных ANR на этапе разработки. Включите его в Application.onCreate() с флагами на дисковые и сетевые операции. При нарушении StrictMode выбрасывает исключение или пишет в logcat.
if (BuildConfig.DEBUG) {
StrictMode.ThreadPolicy.Builder()
.detectDiskReads()
.detectDiskWrites()
.detectNetwork()
.penaltyLog()
.build()
.let { StrictMode.setThreadPolicy(it) }
}
Kotlin Coroutines — стандартный способ асинхронной работы в современных Android-приложениях. Корневой приём: операции ввода-вывода выполняются на Dispatchers.IO, результат передаётся на Dispatchers.Main для обновления UI. Для Flow-подобных сценариев используйте Dispatchers.Default для CPU-интенсивных задач.
RxJava остаётся популярным в легаси-проектах. subscribeOn(Schedulers.io()) и observeOn(AndroidSchedulers.mainThread()) — минимальный набор для предотвращения ANR. Главное правило то же: ни один Observable или Flowable не должен эмитить данные с главного потока.
Firebase Crashlytics с версии SDK 18.4.0 поддерживает мониторинг ANR «из коробки». Для Android 11+ Crashlytics использует системный API ApplicationExitInfo, который предоставляет точную причину завершения: ANR, Crash, или системное убийство. Включите custom ключи с параметрами экрана и состояния для контекстного анализа.
Пять инструментов покрывают все этапы работы с ANR: от отладки на рабочей станции до мониторинга в продакшене. Каждый инструмент решает свою задачу и предоставляет данные для разных сценариев.
| Инструмент | Назначение | Формат данных |
|---|---|---|
| StrictMode | Обнаружение на этапе разработки | Logcat / Exception |
| ANR Watchdog (Android Studio) | Трассировка в реальном времени | Thread dump + timeline |
| Google Play Console | Агрегированная статистика | ANR rate + stack traces |
| Firebase Crashlytics | Продакшен-мониторинг | ApplicationExitInfo |
| adb bugreport | Полный системный отчёт | traces.txt + logcat + dmesg |
Каждый инструмент имеет свою нишу: StrictMode ловит очевидные нарушения на ранних этапах, Crashlytics показывает реальную частоту ANR у пользователей, а adb bugreport даёт максимально полную картину для сложных случаев. Комбинируйте их для полного покрытия.
Firebase Performance отслеживает время отклика UI-потока и автоматически создаёт трейсы для подозрительно долгих операций. Если главный поток блокируется более чем на 500 мс, Performance фиксирует custom trace с именем метода-виновника. Это позволяет обнаруживать ANR-сценарии без участия пользователя и до того, как они станут критическими.
Интеграция с Firebase Crashlytics даёт полную картину: Performance показывает замедления до ANR, а Crashlytics — сам факт зависания. Настройте алерты в Firebase Console на событие ANR rate выше 0.1%, и вы будете получать уведомления о новых проблемах до массовых жалоб пользователей.
Часто задаваемые вопросы
ANR — это зависание, при котором приложение не отвечает, но остаётся в памяти. Crash — полное аварийное завершение с выходом из процесса. ANR можно «пережить», если система или пользователь дождутся ответа, а Crash всегда завершает приложение.
Нет. ANR — не исключение Java/Kotlin, а сигнал системы на уровне процессов (SIGQUIT). Разработчик не может обработать его в коде приложения. Единственный способ реагировать на ANR — анализировать отчёты после перезапуска.
Производительность устройства, версия Android, загруженность CPU и количество фоновых процессов влияют на вероятность ANR. На слабых устройствах та же операция может выполняться в 2–3 раза дольше, превышая 5-секундный лимит.
10 секунд для обычного BroadcastReceiver в onReceive(). Для foreground-служб лимит составляет 20 секунд, а для ContentProvider — нет явного лимита, но блокировка главного потока дольше 5 секунд всё равно вызывает ANR.
Включите StrictMode во всех debug-сборках, добавьте мониторинг через Firebase Crashlytics и используйте adb bugreport, когда ANR случается. Нерегулярные ANR часто связаны с условиями гонки (race condition) или специфическими состояниями сети.
Итоги
Мы разработаем мобильное приложение под ключ
IT Sectr создаёт приложения для iOS и Android для стартапов и бизнеса с 2017 года. Мы проконсультируем вас и предложим наилучшее решение.
Читайте также