ANR (Application Not Responding) — то је системско обавештење платформе Android које се појављује када апликација престане да реагује на кориснички унос дуже од 5 секунди. Према Android Developers, главни узрок су дугачке операције на главном нити, које блокирају обраду дотираја и исцртавање интерфејса. Разумевање механизама ANR-а је неопходно сваком Android програмеру за стварање пријемчивих апликација.
Главно
ANR (Application Not Responding) — то је дијалошки прозор оперативног система Android који се појављује када апликација престане да одговара на кориснички унос. Систем прати време обраде догађаја кроз InputDispatcher: ако дотир или притисак дугмета није обрађен за 5 секунди, Android приказује дијалог са предлогом да се апликација затвори или сачека.
Механизам ANR штити корисничко искуство од замрзлих апликација. Android не дозвољава једној апликацији да блокира цео систем — за разлику од десктоп система, мобилна платформа принудно ограничава време обраде догађаја. 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-а је гарантован пут ка замрзавању.
Унутар BroadcastReceiver-а за пребацивање на позадински нит користите goAsync() или 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 у профилеру. Он аутоматски снима думп нити ако главни нит не одговара дуже од праг времена. Алат приказује временску линију догађаја: које су операције покренуте, који су методи извршени и у којој фази се блокада догодила.
Превенција 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 апликацијама. Основни принцип: улазно-излазне операције се извршавају на 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 нити и аутоматски креира трагове за сумњиво дугачке операције. Ако се главни нит блокира на више од 500 ms, Performance бележи прилагођени траг са називом методе кривца. То омогућава откривање 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. године. Саветоваћемо вас и предложити најбоље решење.
Прочитајте такође