ANR (Application Not Responding) — je systémové upozornění Androidu, které se objeví, když aplikace přestane reagovat na uživatelský vstup déle než 5 sekund. Podle Android Developers jsou hlavní příčinou dlouhé operace na hlavním vlákně, které blokují zpracování dotyků a vykreslování rozhraní. Pochopení mechanismů ANR je nezbytné pro každého Android vývojáře k vytváření responzivních aplikací.
Hlavní body
ANR (Application Not Responding) — je dialogové okno operačního systému Android, které se objeví, když aplikace přestane odpovídat na uživatelský vstup. Systém sleduje dobu zpracování událostí prostřednictvím InputDispatcher: pokud dotyk nebo stisk tlačítka není zpracován do 5 sekund, Android zobrazí dialog s nabídkou zavření nebo vyčkání na aplikaci.
Mechanismus ANR chraní uživatelský zážitek před zaseknutými aplikacemi. Android nedovoluje jedné aplikaci blokovat celý systém — na rozdíl od desktopových OS, mobilní platforma vynuceně omezuje dobu zpracování událostí. BroadcastReceiver má limit 10 sekund a foreground služba 20 sekund.
ANR NENÍ výjimkou v kódu — je to systémový mechanismus na úrovni Linuxových procesů. Android posílá procesu signál SIGQUIT, poté systém uloží zásobník volání všech vláken do souboru traces.txt. Vývojář dostává ANR nikoli jako catch-výjimku, ale jako hlášení po restartu aplikace. Na Androidu 11+ se objevilo API ApplicationExitInfo, které umožňuje programově získat příčinu ukončení procesu, včetně ANR — to zjednodušuje sběr statistik bez ručního parsování traces.txt.
Pět kategorií operací stabilně vede k ANR v Android aplikacích. Každá z nich blokuje hlavní vlákno, bráníc systému zpracovávat vstupní události a překreslovat obrazovku.
Synchrónní HTTP požadavky provedené na UI vlákně — nejčastější příčina ANR u začínajících vývojářů. I rychlý požadavek na server může trvat 1–3 sekundy a při slabém připojení 30 sekund a více. Android výslovně zakazuje síťové operace na hlavním vlákně od API 11, vyhazujíc NetworkOnMainThreadException.
Používejte Coroutines nebo RxJava pro asynchronní volání. Korutiny s dispečerem Dispatchers.IO provádějí požadavek na pozadí a výsledek předávají na hlavní přes Dispatchers.Main. To zcela eliminuje blokování UI vlákna síťovými operacemi.
fun fetchUserData() {
CoroutineScope(Dispatchers.Main).launch {
val result = withContext(Dispatchers.IO) {
api.getUserData() // operace na pozadí
}
updateUI(result) // výsledek na hlavním vlákně
}
}
Zpracování velkých datových polí, parsování JSON nebo XML, práce přímo s bitmapou na hlavním vlákně — druhá nejčastější příčina ANR. I 300 milisekund nepřetržité práce UI vlákna bez návratu do smyčky událostí způsobuje znatelné zpoždění vykreslování a hraniční hodnota 5 sekund je zaznamenána jako ANR.
WorkManager a služby na pozadí jsou určeny k přesunu těžkých výpočtů z hlavního vlákna. Používejte AsyncTask (zastaralý), ListenableFuture nebo Kotlin Flow k přenosu dat po částech bez blokování UI.
Deadlock nastane, když dvě vlákna drží zámky a čekají na sebe. Pokud je jedno z vláken hlavní, systém zaznamená ANR přesně po 5 sekundách. Thread.join(), CountDownLatch.await() a synchronized bloky volané z UI vlákna nesou riziko blokování.
Vyhněte se jakýmkoli blokujícím operacím na hlavním vlákně. Místo synchronized používejte ConcurrentHashMap, místo Thread.join() — korutiny s async/await. Toto pravidlo platí pro každý jazyk v Androidu: Java, Kotlin nebo C++ přes JNI.
BroadcastReceiver se standardně spouští na hlavním vlákně. Pokud je onReceive() zaneprázdněn více než 10 sekund, Android zobrazí ANR. Načítání dat z databáze nebo sítě uvnitř onReceive je zaručenou cestou k zaseknutí.
Použijte goAsync() uvnitř BroadcastReceiver pro přepnutí na vlákno na pozadí nebo registerReceiver s getBackgroundBroadcastReceiver(). To umožňuje zpracování událostí bez blokování UI.
Těžké dotazy na ContentProvider nebo přímá práce s SQLite na UI vlákně — méně zřejmá, ale častá příčina ANR. Při migraci databáze nebo hromadném vkládání tisíců záznamů může doba provádění překročit 5sekundový limit.
Přeneste všechny operace s databází do vláken na pozadí přes Room s suspend funkcemi. Room automaticky kontroluje, že dotaz není prováděn na hlavním vlákně a při porušení vyhazuje výjimku.
Diagnostika ANR se liší od ladění běžných výjimek — nemůžete ANR zachytit v try-catch. Hlavním zdrojem informací je soubor traces.txt, který Android vytváří v okamžiku zamrznutí.
traces.txt obsahuje zásobník volání všech vláken aplikace v okamžiku ANR. Pro čtení souboru z reálného zařízení proveďte příkaz adb bugreport, který shromažďuje úplnou systémovou hlášku včetně všech ANR z poslední doby. Pro emulátor je soubor dostupný v /data/anr/traces.txt. Zásobník volání ukazuje, která metoda se prováděla na hlavním vlákně v okamžiku blokování.
adb bugreport bugreport.zip
unzip -p bugreport.zip "*traces*" > traces.txt
Google Play Console poskytuje sekci ANR & Crash s agregovanými hláškami a frekvencemi chyb. Pro každý ANR je zobrazen zásobník volání a statistiky podle zařízení: model, verze Androidu, region. To umožňuje identifikovat ANR, které závisí na konkrétních zařízeních nebo verzích systému.
Android Studio od roku 2021 obsahuje ANR Watchdog v profilování. Automaticky zaznamenává dump vláken, pokud hlavní vlákno neodpovídá déle než prahový čas. Nástroj zobrazuje časovou osu událostí: jaké operace byly spuštěny, jaké metody byly prováděny a v jaké fázi došlo k blokování.
Prevence ANR je postavena na jednom základním pravidle: hlavní vlákno by mělo zpracovávat pouze události UI. Jakákoli operace trvající déle než 16 milisekund (čas jednoho snímku) by měla být provedena na vlákně na pozadí.
StrictMode — vestavěný nástroj Androidu pro detekci potenciálních ANR ve fázi vývoje. Zapněte jej v Application.onCreate() s příznaky pro diskové a síťové operace. Při porušení StrictMode vyhodí výjimku nebo zapíše do logcat.
if (BuildConfig.DEBUG) {
StrictMode.ThreadPolicy.Builder()
.detectDiskReads()
.detectDiskWrites()
.detectNetwork()
.penaltyLog()
.build()
.let { StrictMode.setThreadPolicy(it) }
}
Kotlin Coroutines — standardní způsob asynchronní práce v moderních Android aplikacích. Základní princip: I/O operace se provádějí na Dispatchers.IO, výsledek se předává na Dispatchers.Main pro aktualizaci UI. Pro Flow scénáře použijte Dispatchers.Default pro CPU náročné úlohy.
RxJava zůstává populární v legacy projektech. subscribeOn(Schedulers.io()) a observeOn(AndroidSchedulers.mainThread()) — minimální sada pro prevenci ANR. Stejné pravidlo: žádný Observable ani Flowable by neměly emitovat data z hlavního vlákna.
Firebase Crashlytics od verze SDK 18.4.0 podporuje monitorování ANR hned z krabice
. Pro Android 11+ Crashlytics používá systémové API ApplicationExitInfo, které poskytuje přesnou příčinu ukončení: ANR, Crash nebo zabití systémem. Zapněte vlastní klíče s parametry obrazovky a stavu pro kontextovou analýzu.
Pět nástrojů pokrývá všechny fáze práce s ANR: od ladění na pracovní stanici až po monitorování v produkci. Každý nástroj řeší svůj úkol a poskytuje data pro různé scénáře.
| Nástroj | Účel | Formát dat |
|---|---|---|
| StrictMode | Detekce ve fázi vývoje | Logcat / Exception |
| ANR Watchdog (Android Studio) | Sledování v reálném čase | Thread dump + timeline |
| Google Play Console | Agregované statistiky | ANR rate + stack traces |
| Firebase Crashlytics | Produkční monitorování | ApplicationExitInfo |
| adb bugreport | Úplná systémová hláška | traces.txt + logcat + dmesg |
Každý nástroj má své místo: StrictMode chytá zřejmá porušení v raných fázích, Crashlytics ukazuje skutečnou frekvenci ANR u uživatelů a adb bugreport poskytuje nejúplnější obrázek pro složité případy. Kombinujte je pro úplné pokrytí.
Firebase Performance sleduje dobu odezvy UI vlákna a automaticky vytváří trasování pro podezřele dlouhé operace. Pokud je hlavní vlákno blokováno více než 500 ms, Performance zaznamená vlastní trasování s názvem metody viníka. To umožňuje detekovat scénáře ANR bez účasti uživatele a dříve, než se stanou kritickými.
Integrace s Firebase Crashlytics dává úplný obrázek: Performance ukazuje zpomalení před ANR a Crashlytics samotný fakt zamrznutí. Nastavte výstrahy v Firebase Console na událost ANR rate nad 0,1 % a budete dostávat upozornění na nové problémy dříve, než přijdou hromadné stížnosti uživatelů.
Časté dotazy
ANR — je zamrznutí, při kterém aplikace neodpovídá, ale zůstává v paměti. Crash — úplné nouzové ukončení s opuštěním procesu. ANR lze přežít
, pokud systém nebo uživatel počká na odpověď, zatímco Crash vždy ukončí aplikaci.
Ne. ANR není výjimkou Java/Kotlin, ale systémovým signálem na úrovni procesů (SIGQUIT). Vývojář jej nemůže zpracovat v kódu aplikace. Jediný způsob, jak reagovat na ANR, je analyzovat hlášení po restartu.
Výkon zařízení, verze Androidu, zatížení CPU a počet procesů na pozadí ovlivňují pravděpodobnost ANR. Na slabších zařízeních může stejná operace trvat 2–3krát déle a překročit 5sekundový limit.
10 sekund pro běžný BroadcastReceiver v onReceive(). Pro foreground služby je limit 20 sekund a pro ContentProvider neexistuje explicitní limit, ale blokování hlavního vlákna déle než 5 sekund stejně způsobí ANR.
Zapněte StrictMode ve všech debug sestaveních, přidejte monitorování přes Firebase Crashlytics a používejte adb bugreport, když ANR nastane. Nepravidelné ANR často souvisí s race condition nebo specifickými stavy sítě.
Shrnutí
Vyvineme mobilní aplikaci na klíč
IT Sectr vytváří aplikace pro iOS a Android pro startupy a podniky od roku 2017. Poradíme vám a navrhneme nejlepší řešení.
Přečtěte si také