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. При миграция на база данни или масово вмъкване на хиляди записи времето за изпълнение може да надхвърли 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 в профилиращия инструмент. Той автоматично записва dump на нишките, ако главната нишка не отговаря повече от праговото време. Инструментът показва времева линия на събитията: кои операции са стартирани, кои методи са се изпълнявали и на кой етап е настъпило блокирането.
Профилактиката на 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 приложения. Основен похват: I/O операциите се изпълняват на 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 или системно убиване. Включете собствени ключове с параметри на екрана и състоянието за контекстуален анализ.
Пет инструмента покриват всички етапи на работа с 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-нишката и автоматично създава traces за подозрително дълги операции. Ако главната нишка блокира за повече от 500 ms, Performance записва персонализиран 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 г. Ще ви консултираме и ще предложим най-доброто решение.
Прочетете също