Когда пользователь открывает приложение, нажимает на кнопку — и ничего не происходит несколько секунд, Android начинает считать, что “приложение не отвечает”. Через 5 секунд на главном потоке система показывает диалог:

“Приложение не отвечает. Закрыть?”

Это и есть ANR (Application Not Responding).

Как Android определяет ANR

ANR — это не исключение и не crash. Это watchdog-механизм системы, который следит за тем, что главный поток (UI thread) не блокируется дольше допустимого времени:

Сценарий

Таймаут

UI-операция (например, нажатие кнопки)

5 секунд

BroadcastReceiver

10 секунд

Service

20 секунд

Когда время превышено, система пишет traces.txt, где сохраняется stacktrace всех потоков, особенно главного (main).

Типичные причины ANR

  1. Тяжёлая операция в UI-потоке -> Парсинг JSON, чтение из БД, сетевой вызов.

  2. Синхронные вызовы в onCreate / onResume -> Инициализация SDK, feature-флагов, heavy DI.

  3. Долгий BroadcastReceiver или Service -> Например, обработка пуша внутри BroadcastReceiver вместо JobIntentService.

  4. Мёртвые блокировки (deadlocks) -> Несогласованные synchronized или mutex между потоками.

  5. UI thread starvation -> Flood event loop’а — много post() или invalidate().

Как анализировать ANR

1. Через Google Play Console

  • Раздел Android Vitals → ANRs

  • Фильтры по версии, устройству, стеку.

2. Через traces.txt

Файл находится по пути: /data/anr/traces.txt или в логе: E/ActivityManager: ANR in <package>

3. Через Firebase / Sentry

  • Подключите anr мониторинг (Performance Monitoring / ANR Handler)

  • Можно собирать stacktrace в реальном времени и привязывать к аналитическим событиям.

Best Practices: как не попасть в ANR

. Держите UI-поток чистым

  • Все тяжёлые операции → Dispatchers.IO или Default.

  • Пример:

viewModelScope.launch(Dispatchers.IO) {
    val result = repository.loadData()
    withContext(Dispatchers.Main) { updateUi(result) }
}

2. Не инициализируйте SDK синхронно

  • Любые внешние SDK, Firebase, Remote Config, Ads — инициализировать асинхронно или через App Startup.

3. Избегайте runBlocking и Thread.sleep()

  • Особенно в onCreate и onResume.

  • Вместо этого — suspend функции и delay().

 4. Избегайте deadlock

  • Никогда не держите synchronized между main и background thread.

  • Используйте Mutex и withLock.

Библиотеки и инструменты для работы с ANR

ANR‑WatchDog

Что это: простая библиотека-watchdog, которая запускает отдельный поток, ставит задачу на UI-потоке и проверяет, был ли UI-поток заблокирован дольше заданного таймаута. 

Преимущества:

  • Быстро подключается (new ANRWatchDog().start();) 

  • При срабатывании выдаёт исключение ANRError с снепшотом всех потоков и стеков — удобно передать в Crashlytics или другой репортинг. 

    Как использовать: можно как дополнительный внутренний контроль, особенно полезен в debug/alpha-сборках, чтобы поймать “потенциальные” ANR-ситуации до того, как они попадут в продакшн.

ANR‑Spy

Что это: библиотека, ориентированная на обнаружение блокировок UI-потока (“приближающихся ANR”), с возможностью интеграции с Firebase Crashlytics и отправки событий перед тем, как система покажет диалог ANR. 

Преимущества:

  • Позволяет задать свой таймаут (например, 3-4 секунд) и фиксировать блокировки. 

  • Можно настроить “раннее предупреждение” — сработать до того, как Google Play сочтёт это плохим поведением.

    Минусы / моменты:

  • Это не “официальный” механизм системы, может не покрывать все случаи ANR на всех версиях Android.

  • Требует настройки: интеграция с репортингом, сбор стеков.

    Когда использовать: как часть internal monitoring SDK, особенно если хочешь ловить “почти ANR” и реагировать до того, как пользователь увидит диалог.

Firebase Crashlytics (и встроенный ANR-репортинг)

Что это: не библиотека исключительно для ANR, но мощный инструмент для отчётности и диагностики ANR-событий в продакшн-приложениях. Документация подробно описывает, как Crashlytics маркирует потоки с тегами Triggered ANR, Deadlocked и помогает разобраться с причинами. 

Почему стоит:

  • Удобно интегрируется с остальными crash/bug-репортами — один канал мониторинга для всех ошибок, включая ANR.

  • Позволяет связывать ANR с конкретными версиями, устройствами, и видеть статистику.

    Лучшее применение: сочетать с internal monitoring (например, ANR-WatchDog или ANR-Spy) + визуализацией (через ClickHouse → Grafana) + линией репортов в Crashlytics.

Как выбрать и комбинировать библиотеки

Цель

Инструмент

Почему

Обнаружить блокировки UI-потока до ANR

ANR-Spy

Позволяет оперативно реагировать

Поддержка мониторинга в debug/internal сборках

ANR-WatchDog

Лёгкая и быстрая проверка

Сбор статистики ANR в продакшн, репорты

Firebase Crashlytics

Интеграция + аналитика

Визуализация и дашборд (не библиотека, но важно)

ClickHouse + Grafana

Связь с бизнес-метриками

Рекомендация:

  1. Включи ANR-WatchDog в debug/alpha-сборках — пусть ранние проверки ловят потенциальные блокировки.

  2. В продакшн-версии подключи ANR-Spy + Crashlytics — чтобы фиксировать и анализировать реальные случаи.

  3. Собирай метрики (ANR rate, block time, версия) в вашу систему (ClickHouse) и выводи в дашборде Grafana. Это даёт вам “радар” производительности и связь с бизнес-метриками.

Как обучить тестировщиков находить ANR

Одна из самых частых проблем — тестировщики замечают “зависание”, но не понимают, что это ANR, и не фиксируют его корректно.

Задача разработчика — дать QA понятный чек-лист и инструменты, чтобы они могли не просто заметить фриз, а воспроизвести, зафиксировать и отправить диагностические данные.

1. Как отличить ANR от обычного лага

Признак

ANR

Просто лаг

Интерфейс полностью “застыл”, кнопки не нажимаются

⚠️ может реагировать

Через 5–10 секунд появляется системное окно “Приложение не отвечает”

После этого приложение закрывается или “оживает”

⚠️ иногда да

В логах есть “ANR in com.example.app

2.Как правильно заводить баг - Пример шаблона тикета для QA:

Название: [ANR] Зависание экрана PDP после открытия карточки товара

Шаги:

  1. Открыть приложение

  2. Перейти в “Категории → Телефоны”

  3. Выбрать любой товар

  4. Наблюдать зависание 5–6 секунд

Ожидаемый результат: экран отображается мгновенно.

Фактический результат: приложение не реагирует, через 5 секунд — системный диалог ANR.

Дополнительно:

  • traces.txt из bugreport

  • версия приложения

  • устройство и Android API

  • лог “E/ActivityManager: ANR in …”

Обучение QA команде

Проведите короткий воркшоп:

  1. Объяснить механику ANR (5s / 10s / 20s таймаут)

  2. Показать примеры на тестовом экране — искусственно заблокировать Thread.sleep(6000)

  3. Научить собирать bugreport и логи

  4. Объяснить бизнес-ценность: ANR = потерянная сессия пользователя

Как встроить в QA-процессы

Этап

Действие

Ответственный

Smoke тестирование

Проверить ключевые экраны на лаги > 4 сек

QA

Regression

Проверить старые ANR-тикеты перед релизом

QA Lead

Post-release

Отслеживать новые ANR в Crashlytics / Grafana

QA + Dev

Еженедельный отчёт

ANR rate на 1000 сессий

QA Analyst

Как связать ANR с бизнес-метриками

  • ANR = снижение session length и retention.

  • Пользователь, увидевший ANR, с вероятностью 60 % не откроет приложение в течение 7 дней.

  • ANR rate > 0.47 % — Google Play может понизить внутренний рейтинг качества.

  • Поэтому снижение ANR rate — это инвестиция в удержание пользователей.

Интеграция с Performance Dashboard

Если у вас уже есть дашборд по производительности (например, в Grafana), добавьте:

  • ANR rate per screen / per team

  • Avg UI thread block time

  • Correlation с событиями (например, “ANR → exit”)

SQL-пример для ClickHouse:

SELECT
  screen_name,
  countIf(event_name = 'anr_detected') / count() AS anr_rate,
  quantileTDigest(0.9)(block_time_ms) AS p90_block_time
FROM app_performance
GROUP BY screen_name
ORDER BY anr_rate DESC

Выводы

  • ANR — это не просто “фриз”, это потерянный пользователь.

  • Главный поток должен быть свободен и легок, как good UX.

  • Мониторьте, анализируйте, автоматизируйте.

  • И помните: “ANR — это crash, только тихий.”

Комментарии (0)