ANR (Application Not Responding) — е системно известие на Android, което се появява, когато приложението не реагира на въвеждане в продължение на 5 секунди. За разлика от гличовете (логически грешки без блокиране на UI) и лаговете (забавяне без пълно спиране), ANR е критична повреда, регистрирана от операционната система: Android показва диалог „Приложението не отговаря“ с предложение за затваряне или изчакване. Според Android Vitals Documentation, приложенията с ANR процент над 0,5% имат по-нисък рейтинг в Google Play и могат да бъдат скрити от препоръките. Диагностиката включва анализ на /data/anr/traces.txt, използване на StrictMode и профилиране на главната нишка.
Основни точки
ANR (Application Not Responding) — е механизъм за защита на потребителя в Android, който се активира, когато приложението спре да реагира на въвеждане. Системта следи времето за обработка на събития: ако BroadcastReceiver не завърши onReceive в рамките на 10 секунди, Service не се върне от onCreate в рамките на 20 секунди, а ContentProvider не отговори в рамките на 15 секунди — Android генерира ANR.
Когато възникне ANR, Android показва системен диалог над всички прозорци: „Приложението не отговаря. Да го затворите ли или да изчакате?“. Потребителят може да затвори приложението или да изчака възстановяването му. Ако ANR се повтаря често, потребителят изтрива приложението. Google Play взема предвид ANR процента — процента сесии с ANR — в алгоритмите за класиране.
На iOS няма аналог на ANR със системен диалог. Вместо това Apple използва Watchdog, който прекратява процеса на приложението с код 0x8badf00d. Потребителят не вижда диалог — приложението просто се затваря към началния екран. Това прави ANR на Android по-забележим за потребителя, но дава на системата повече информация за диагностика.
ANR възниква, когато системата следи таймаут за един от четирите типа компоненти. Всеки компонент има свой собствен времеви лимит.
BroadcastReceiver се изпълнява в главната нишка. Ако onReceive стартира синхронна мрежова заявка, дълга операция за запис в базата данни или чака блокиране — след 10 секунди възниква ANR. Решение: използвайте goAsync() и WorkManager за фонова обработка. Типичен сценарий — получаване на Push известие от FCM и синхронно запазване в Room.
Service.onCreate и Service.onStartCommand имат лимит от 20 секунди. Ако услугата стартира тежка инициализация (зареждане на библиотеки, четене на конфигурация от мрежата) в главната нишка — ANR е неизбежен. Използвайте IntentService (остарял) или WorkManager за гарантирано изпълнение във фонова нишка.
ContentProvider.onCreate се изпълнява преди извикването на Application.onCreate и има лимит от 15 секунди. Ако доставчикът извършва миграция на база данни, зареждане на речници или инициализация на SDK от мрежата — това причинява ANR при стартиране на приложението. Решение: ленива инициализация, прехвърляне на тежки операции към WorkManager.
Android предоставя няколко инструмента за анализ на ANR: от системни логове до специализирани библиотеки.
При всеки ANR Android запазва файла /data/anr/traces.txt с дамп на стековете на всички нишки на приложението. Намерете нишката „main“ — последният метод в стека показва причината. Типични модели: Thread.sleep(), InputStream.read(), BinderProxy.transact(). За извличане на файла от устройството използвайте adb със суперпотребителски права.
Firebase Crashlytics автоматично събира ANR и ги показва в таблото за управление заедно с проследяване. За Android 11+ ANR отчетите идват с пълен стек на главната нишка. Интеграцията изисква добавяне на зависимост и инициализация на FirebaseApp в Application.onCreate.
CPU Profiler в Android Studio ви позволява да запишете проследяване на работата на приложението и да видите кои методи заемат процесорно време. Включете „Record with method traces“ и възпроизведете сценария, причиняващ ANR. На времевата линия ще бъде видимо кои методи са се изпълнявали в главната нишка в момента на замръзване.
Пример за интеграция на Firebase Crashlytics за събиране на ANR на Android:
class App : Application() {
override fun onCreate() {
super.onCreate()
FirebaseApp.initializeApp(this)
FirebaseCrashlytics.getInstance()
.setCrashlyticsCollectionEnabled(true)
StrictMode.setThreadPolicy(StrictMode.ThreadPolicy.Builder()
.detectAll()
.penaltyLog()
.build())
}
}
Отстраняването на ANR означава преди всичко прехвърляне на всички дълги операции от главната нишка към фоновите нишки. Нека разгледаме конкретни техники за всеки тип компонент.
WorkManager — препоръчителното от Google решение за фонова работа. Гарантира изпълнение на задачата във фонова нишка, като взема предвид състоянието на устройството. За разлика от Service, WorkManager не блокира главната нишка и е устойчив на рестартиране на приложението. За BroadcastReceiver използвайте goAsync() и предайте резултата PendingResult на WorkManager.
Стартирайте всички мрежови заявки, работа с база данни и файлови операции с Dispatchers.IO. Главната нишка трябва само да актуализира UI. Използвайте viewModelScope за автоматично отмяна на корутините при унищожаване на Activity. Избягвайте runBlocking() в какъвто и да е контекст — това е синхронно блокиране на текущата нишка.
Ако ContentProvider извършва дълга инициализация, използвайте механизъм за закъсняло зареждане: създайте доставчик, който незабавно връща данни, и стартирайте тежката инициализация чрез WorkManager със закъснение. Това предотвратява ANR при стартиране на приложението, когато системата е най-чувствителна към закъснения.
Пример за правилно използване на BroadcastReceiver с goAsync в Android:
class FcmReceiver : BroadcastReceiver() {
override fun onReceive(context: Context?, intent: Intent?) {
val pendingResult = goAsync()
WorkManager.getInstance(context!!)
.enqueue(OneTimeWorkRequest.from(NotificationWorker::class.java))
pendingResult.finish()
}
}
Най-добрият начин за борба с ANR е предотвратяването на появата им в етапа на разработка чрез инструменти и архитектурни решения.
StrictMode с активирани политики detectNetwork() и detectDiskReads()/detectDiskWrites() открива потенциални ANR в етапа на разработка. В Debug компилация задайте penaltyDeath — всяко нарушение ще доведе до незабавен срив и разработчикът ще види проблема преди комитване.
Firebase Performance следи времето за изпълнение на ключови операции и показва кои сценарии надхвърлят прага на ANR. Настройте персонализирани проследявания за всеки екран и мрежова заявка. Ако времето за изпълнение надвишава 3 секунди — това е потенциален ANR, който изисква оптимизация.
Симулирайте бавни условия: ограничете скоростта на мрежата чрез Network Link Conditioner на iOS или Android Emulator. Забавете четенето от диска чрез емулация на бавна памет. ANR често се появява точно при такива условия, на бързите устройства на разработчика не е видим.
Често задавани въпроси
Android изрично следи времето за обработка на събития в главната нишка и показва диалог ANR. iOS използва Watchdog, който принудително затваря приложението при замръзване за повече от 10–20 секунди. ANR е характеристика на архитектурата на Android, където няколко компонента (BroadcastReceiver, Service) имат строги таймаути.
На Android 11+ можете да получите ANR дамп чрез adb shell dumpsys dropbox --print data_app_anr. На Android 10 и по-долу без root няма достъп до /data/anr/traces.txt. Използвайте Firebase Crashlytics — автоматично събира ANR отчети за Android 11+.
Google Play препоръчва ANR процент под 0,5% — тоест не повече от 5 ANR на 1000 сесии. Приложение с процент над 1% получава предупреждение в Google Play Console и може да бъде скрито от препоръки. В идеалния случай ANR процентът трябва да бъде под 0,1%.
Корутината сама по себе си не блокира нишката. Но ако вътре в корутината се изпълнява runBlocking на главната нишка или корутината е стартирана с Dispatchers.Main и извършва дълга CPU операция — това ще причини ANR. Използвайте Dispatchers.IO за вход-изход и Dispatchers.Default за изчисления.
Използвайте Android Emulator с профил „Slow Network“ или напишете тест, който извиква Thread.sleep(6000) на главната нишка. Стартирайте приложението чрез Debug и след 5 секунди ще видите диалог ANR. Проверете дали в logcat се е появил запис за ANR с проследяване.
Обобщение
Ще разработим мобилно приложение под ключ
IT Sectr създава iOS и Android приложения за стартъпи и бизнеси от 2017 г. Ще ви консултираме и ще предложим най-доброто решение.
Прочетете също