ANR в разработке под Android — что это такое, причины и способы исправления

Автор: IT Sectr Опубликовано: 2026-03-28 Время чтения: 9 мин

ANR (Application Not Responding) — это системное уведомление Android, которое появляется, когда приложение перестаёт реагировать на пользовательский ввод дольше 5 секунд. По данным Android Developers, основная причина — долгие операции на главном потоке, блокирующие обработку касаний и отрисовку интерфейса. Понимание механизмов ANR необходимо каждому Android-разработчику для создания отзывчивых приложений.

Главное

  • ANR — системное предупреждение Android при зависании приложения дольше 5 секунд
  • Главный поток (UI-поток) — единственное место, где блокировка приводит к ANR
  • InputDispatcher — компонент системы, фиксирующий задержку ввода и инициирующий ANR
  • traces.txt — ключевой файл для диагностики причины зависания на устройстве
  • StrictMode — встроенный инструмент Android для обнаружения долгих операций на UI-потоке

Что такое ANR

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

Пять категорий операций стабильно приводят к ANR в Android-приложениях. Каждая из них блокирует главный поток, не давая системе обрабатывать события ввода и перерисовку экрана.

Сетевые запросы на главном потоке

Синхронные HTTP-запросы, выполненные на UI-потоке, — самая частая причина ANR у начинающих разработчиков. Даже быстрый запрос к серверу может занять 1–3 секунды, а при плохом соединении — 30 секунд и больше. Android явно запрещает сетевые операции на главном потоке начиная с API 11, выбрасывая NetworkOnMainThreadException.

Используйте Coroutines или RxJava для асинхронных вызовов. Корутины с диспетчером Dispatchers.IO выполняют запрос в фоновом потоке, а результат передают на главный через Dispatchers.Main. Это полностью исключает блокировку UI-потока сетевыми операциями.

kotlin
fun fetchUserData() {
    CoroutineScope(Dispatchers.Main).launch {
        val result = withContext(Dispatchers.IO) {
            api.getUserData() // фоновая операция
        }
        updateUI(result) // результат на главном потоке
    }
}

Интенсивные вычисления на UI-потоке

Обработка больших массивов данных, парсинг JSON или XML, работа с bitmap напрямую на главном потоке — вторая по частоте причина ANR. Даже 300 миллисекунд непрерывной работы UI-потока без возврата в цикл событий вызывают заметную задержку отрисовки, а пограничное значение в 5 секунд фиксируется как ANR.

WorkManager и фоновые сервисы предназначены для выноса тяжёлых вычислений из главного потока. Используйте AsyncTask (устарел), ListenableFuture или Kotlin Flow для передачи данных порциями, не блокируя UI.

Блокировки синхронизации и Deadlock

Deadlock возникает, когда два потока удерживают блокировки и ждут друг друга. Если один из потоков — главный, система фиксирует ANR ровно через 5 секунд. Thread.join(), CountDownLatch.await() и synchronized-блоки, вызываемые с UI-потока, несут риск блокировки.

Избегайте любых блокирующих операций на главном потоке. Вместо synchronized используйте ConcurrentHashMap, вместо Thread.join() — корутины с async/await. Это правило действует для любого языка в Android: Java, Kotlin или C++ через JNI.

Долгая работа BroadcastReceiver

BroadcastReceiver выполняется на главном потоке по умолчанию. Если onReceive() занят более 10 секунд, Android показывает ANR. Загрузка данных из БД или сети внутри onReceive — гарантированный путь к зависанию.

Используйте goAsync() внутри BroadcastReceiver для переключения в фоновый поток, либо registerReceiver с getBackgroundBroadcastReceiver(). Это позволяет обрабатывать события без блокировки UI.

ContentProvider и SQLite на главном потоке

Тяжёлые запросы к ContentProvider или прямая работа с SQLite на UI-потоке — менее очевидная, но частая причина ANR. При миграции базы данных или bulk-вставке тысяч записей время выполнения может превысить 5-секундный лимит.

Переносите все операции с базой данных в фоновые потоки через Room с suspend-функциями. Room автоматически проверяет, что запрос не выполняется на главном потоке, и выбрасывает исключение при нарушении.

Как диагностировать ANR

Диагностика ANR отличается от отладки обычных исключений — вы не можете поймать ANR в try-catch. Основной источник информации — файл traces.txt, который Android создаёт в момент зависания.

traces.txt содержит стек вызовов всех потоков приложения на момент ANR. Чтобы прочитать файл с реального устройства, выполните команду adb bugreport, которая собирает полный отчёт системы, включая все ANR за последнее время. Для эмулятора файл доступен в /data/anr/traces.txt. Стек вызовов показывает, какой метод выполнялся на главном потоке в момент блокировки.

text
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

Профилактика ANR строится на одном фундаментальном правиле: главный поток должен только обрабатывать события UI. Любая операция дольше 16 миллисекунд (время одного кадра) должна выполняться в фоновом потоке.

StrictMode — автоматическая проверка

StrictMode — встроенный инструмент Android для обнаружения потенциальных ANR на этапе разработки. Включите его в Application.onCreate() с флагами на дисковые и сетевые операции. При нарушении StrictMode выбрасывает исключение или пишет в logcat.

kotlin
if (BuildConfig.DEBUG) {
    StrictMode.ThreadPolicy.Builder()
        .detectDiskReads()
        .detectDiskWrites()
        .detectNetwork()
        .penaltyLog()
        .build()
        .let { StrictMode.setThreadPolicy(it) }
}

Асинхронные паттерны: Coroutines и RxJava

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

Пять инструментов покрывают все этапы работы с 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 Monitoring

Firebase Performance отслеживает время отклика UI-потока и автоматически создаёт трейсы для подозрительно долгих операций. Если главный поток блокируется более чем на 500 мс, Performance фиксирует custom trace с именем метода-виновника. Это позволяет обнаруживать ANR-сценарии без участия пользователя и до того, как они станут критическими.

Интеграция с Firebase Crashlytics даёт полную картину: Performance показывает замедления до ANR, а Crashlytics — сам факт зависания. Настройте алерты в Firebase Console на событие ANR rate выше 0.1%, и вы будете получать уведомления о новых проблемах до массовых жалоб пользователей.

Часто задаваемые вопросы

Чем ANR отличается от Crash?

ANR — это зависание, при котором приложение не отвечает, но остаётся в памяти. Crash — полное аварийное завершение с выходом из процесса. ANR можно «пережить», если система или пользователь дождутся ответа, а Crash всегда завершает приложение.

Можно ли поймать ANR через try-catch?

Нет. ANR — не исключение Java/Kotlin, а сигнал системы на уровне процессов (SIGQUIT). Разработчик не может обработать его в коде приложения. Единственный способ реагировать на ANR — анализировать отчёты после перезапуска.

Почему ANR появляется на одних устройствах, но не на других?

Производительность устройства, версия Android, загруженность CPU и количество фоновых процессов влияют на вероятность ANR. На слабых устройствах та же операция может выполняться в 2–3 раза дольше, превышая 5-секундный лимит.

Какой лимит времени у BroadcastReceiver до ANR?

10 секунд для обычного BroadcastReceiver в onReceive(). Для foreground-служб лимит составляет 20 секунд, а для ContentProvider — нет явного лимита, но блокировка главного потока дольше 5 секунд всё равно вызывает ANR.

Что делать, если ANR происходит редко и не воспроизводится?

Включите StrictMode во всех debug-сборках, добавьте мониторинг через Firebase Crashlytics и используйте adb bugreport, когда ANR случается. Нерегулярные ANR часто связаны с условиями гонки (race condition) или специфическими состояниями сети.

Итоги

  • ANR — системный механизм Android, срабатывающий при блокировке главного потока дольше 5 секунд
  • Главный поток должен заниматься только UI — все остальные операции выносятся в фоновые потоки
  • Диагностика ANR ведётся через traces.txt, Google Play Console и Firebase Crashlytics
  • StrictMode обнаруживает потенциальные ANR на этапе разработки без запуска на реальном устройстве
  • Coroutines с Dispatchers.IO — стандартный способ асинхронной работы в современных Android-проектах
  • BroadcastReceiver требует goAsync() или фонового регистратора для работы дольше 10 секунд
  • ANR в продакшене мониторится через Crashlytics и встроенный API ApplicationExitInfo на Android 11 и выше

Мы разработаем мобильное приложение под ключ

IT Sectr создаёт приложения для iOS и Android для стартапов и бизнеса с 2017 года. Мы проконсультируем вас и предложим наилучшее решение.

Обсудить проект

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