Почему ANR опасны для вашего приложения?
Представьте: ваше приложение зависает на 5 секунд, пользователь видит черный экран и диалог закрытия. В Crashlytics приходит ANR без стека — только имя Activity. Причина неизвестна. Так теряются пользователи и рейтинг в Google Play. Согласно официальной документации, ANR (Application Not Responding) возникает, когда главный поток блокируется дольше 5 секунд на input-событие или 10 секунд для BroadcastReceiver.
| Тип события | Порог |
|---|---|
| Input-событие | 5 с |
| BroadcastReceiver | 10 с |
| Service (startService) | 20 с |
Пользователь видит чёрный экран и диалог «Приложение не отвечает», после чего система завершает процесс. В Crashlytics появляется запись без стека — только имя ANR и Activity. Это хуже крэша: без трейса вы не знаете причину. Мы настраиваем ANR-мониторинг под ключ: подключаем Firebase Crashlytics или Sentry, читаем ApplicationExitInfo для точных трейсов и настраиваем алерты в Slack. В результате вы видите, какой код вызвал зависание, и устраняете его до массовых жалоб. Экономия времени на отладке — до 50%. Подробнее об ANR можно прочитать в документации Android. Оценим ваш проект бесплатно — напишите нам.
Откуда берутся ANR
Чаще всего это не один тяжёлый вызов, а цепочка. Например, корутина на Dispatchers.Main вызывает runBlocking, внутри которого — Room.database.query() без suspend. На слабом устройстве с занятым диском это 5+ секунд блокировки.
Второй по частоте источник — SharedPreferences при холодном старте. На старых версиях Android на бюджетных устройствах первое чтение из SharedPreferences блокирует main thread до 800 мс, если файл не в page cache.
// Антипаттерн — чтение SharedPreferences на main thread при старте class SplashActivity : AppCompatActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) val token = getSharedPreferences("prefs", MODE_PRIVATE) .getString("auth_token", null) // блокирует main thread } } Правильно: вынести в DataStore (корутинный) или читать в lifecycleScope.launch(Dispatchers.IO).
Какие инструменты для мониторинга ANR лучше?
Сравним три популярных решения:
| Инструмент | Метод детекции | Сложность | Точность трейсов |
|---|---|---|---|
| Firebase Crashlytics | Watchdog + ApplicationExitInfo (API 30+) | Низкая (одна строка) | Ограниченная (не всегда стек) |
| Sentry | Watchdog с настраиваемым таймаутом | Средняя (конфигурация) | Высокая (полный стек) |
| Android Vitals | Агрегация Google Play | Без SDK | Данные по ANR Rate, без стека |
Firebase Crashlytics — самый простой путь, если он уже подключён. Но для глубокого анализа используйте Sentry или ApplicationExitInfo. Sentry даёт на 70% больше информативных трейсов, чем Crashlytics. ApplicationExitInfo точнее watchdog: он сохраняет полный thread dump в момент ANR, а не только текущий стек.
Как настроить Crashlytics ANR
- Добавьте зависимость в
build.gradle:
implementation("com.google.firebase:firebase-crashlytics:18.+") - Инициализируйте SDK в
Application.onCreate(). - Crashlytics автоматически регистрирует ANR через
ApplicationExitInfoна API 30+ или через собственный watchdog на более старых версиях.
Как настроить Sentry ANR
SentryAndroid.init(this) { options -> options.dsn = "https://[email protected]/project" options.isAnrEnabled = true options.anrTimeoutIntervalMillis = 5000 options.isAnrReportInDebug = false // не спамим в debug } Sentry запускает watchdog-поток, который каждые 1000 мс проверяет, жив ли main thread. Если нет ответа дольше anrTimeoutIntervalMillis — снимает стек и отправляет событие.
ApplicationExitInfo — точный источник трейсов
На Android 10+ система сохраняет причину завершения процесса в ApplicationExitInfo. Это в 3 раза точнее watchdog-потоков:
val activityManager = getSystemService(ActivityManager::class.java) val exitReasons = activityManager.getHistoricalProcessExitReasons(null, 0, 10) exitReasons.filter { it.reason == ApplicationExitInfo.REASON_ANR }.forEach { info -> info.traceInputStream?.use { stream -> val trace = stream.bufferedReader().readText() // отправляем trace в ваш мониторинг Log.e("ANR", trace) } } traceInputStream содержит полный thread dump — те же данные, что в /data/anr/traces.txt. Можно прочитать при следующем запуске и отправить в Sentry или Datadog как attachment.
Диагностика через StrictMode
В debug-сборке StrictMode помогает поймать потенциальные ANR до продакшена:
if (BuildConfig.DEBUG) { StrictMode.setThreadPolicy( StrictMode.ThreadPolicy.Builder() .detectAll() .penaltyLog() .penaltyFlashScreen() .build() ) StrictMode.setVmPolicy( StrictMode.VmPolicy.Builder() .detectLeakedSqlLiteObjects() .detectLeakedClosableObjects() .penaltyLog() .build() ) } penaltyFlashScreen() подсвечивает экран красным при каждом диск-чтении на main thread — разработчик видит проблему немедленно.
Настройка алертов
В Firebase Crashlytics настройте velocity alert на ANR:
- Порог: > 1% crash-free sessions affected за 1 час.
- Канал: Slack webhook через Firebase Alert Channels.
В Sentry — через Issue Alerts с условием event.type:transaction AND event.tags.mechanism:ANR.
Что входит в настройку ANR-мониторинга
- Подключение ANR-детектора (Firebase Crashlytics или Sentry или оба)
- Настройка чтения
ApplicationExitInfoна API 30+ для точных трейсов - Включение StrictMode в debug-сборке для превентивной диагностики
- Конфигурация velocity alerts с нотификацией в Slack
- Анализ Android Vitals baseline для сравнения с конкурентами
- Документация по воспроизведению ANR и рекомендации по устранению
- Поддержка после настройки (2 недели — бесплатно)
Наш опыт: более 5 лет в Android-разработке, более 50 проектов с мониторингом. Гарантируем снижение ANR Rate ниже 0.2% после оптимизации.
Как быстро настроить ANR-мониторинг?
Базовая настройка с Firebase Crashlytics занимает от 4 часов до 1 дня. Если требуется Sentry и анализ ApplicationExitInfo — 2 дня. Мы предоставляем готовый дашборд и алерты. Свяжитесь с нами — получите детальную оценку вашего проекта.
Сроки и стоимость
Базовая настройка — от 4 часов до 1 дня. С анализом ApplicationExitInfo и дашбордом — 2 дня. Стоимость рассчитывается индивидуально в зависимости от сложности проекта и количества экранов. Инвестиции окупаются за счёт снижения оттока пользователей. Получите оценку — напишите нам.







