ANR (Application Not Responding) — je systémové oznámení Androidu, které se zobrazí, když aplikace nereaguje na vstup po dobu 5 sekund. Na rozdíl od glitchů (logické chyby bez blokování UI) a lagů (zpomalení bez úplného zastavení) je ANR kritická chyba zaznamenaná operačním systémem: Android zobrazí dialog „Aplikace nereaguje“ s nabídkou k zavření nebo čekání. Podle Android Vitals Documentation mají aplikace s mírou ANR nad 0,5 % nižší hodnocení v obchodě Google Play a mohou být skryty z doporučení. Diagnostika zahrnuje analýzu /data/anr/traces.txt, použití StrictMode a profilování hlavního vlákna.
Hlavní body
ANR (Application Not Responding) — je mechanismus ochrany uživatele v Androidu, který se aktivuje, když aplikace přestane reagovat na vstup. Systém sleduje dobu zpracování událostí: pokud BroadcastReceiver nedokončí onReceive do 10 sekund, Service se nevrátí z onCreate do 20 sekund a ContentProvider neodpoví do 15 sekund — Android vygeneruje ANR.
Když dojde k ANR, Android zobrazí systémový dialog nad všemi okny: „Aplikace nereaguje. Chcete ji zavřít nebo počkat?“. Uživatel může aplikaci zavřít nebo počkat na její obnovení. Pokud se ANR často opakuje, uživatel aplikaci smaže. Google Play zohledňuje míru ANR — procento relací s ANR — v algoritmech řazení.
Na iOS neexistuje ekvivalent ANR se systémovým dialogem. Místo toho Apple používá Watchdog, který ukončí proces aplikace kódem 0x8badf00d. Uživatel nevidí žádný dialog — aplikace se jednoduše zavře na hlavní obrazovku. To činí ANR na Androidu pro uživatele viditelnějším, ale poskytuje systému více informací pro diagnostiku.
K ANR dochází, když systém sleduje časový limit pro jednu ze čtyř typů komponent. Každá komponenta má svůj vlastní časový limit.
BroadcastReceiver se spouští v hlavním vlákně. Pokud onReceive spustí synchronní síťový požadavek, dlouhou operaci zápisu do databáze nebo čeká na blokování — po 10 sekundách dojde k ANR. Řešení: použijte goAsync() a WorkManager pro zpracování na pozadí. Typický scénář — přijetí Push oznámení z FCM a synchronní ukládání do Room.
Service.onCreate a Service.onStartCommand mají limit 20 sekund. Pokud služba spustí těžkou inicializaci (načítání knihoven, čtení konfigurace ze sítě) v hlavním vlákně — ANR je nevyhnutelný. Použijte IntentService (zastaralý) nebo WorkManager pro zaručené provedení ve vlákně na pozadí.
ContentProvider.onCreate se provádí před voláním Application.onCreate a má limit 15 sekund. Pokud poskytovatel provádí migraci databáze, načítání slovníků nebo inicializaci SDK ze sítě — způsobuje to ANR při spouštění aplikace. Řešení: líná inicializace, přesun těžkých operací do WorkManager.
Android poskytuje několik nástrojů pro analýzu ANR: od systémových protokolů po specializované knihovny.
Při každém ANR Android ukládá soubor /data/anr/traces.txt s výpisem zásobníků všech vláken aplikace. Najděte vlákno „main“ — poslední metoda v zásobníku ukazuje příčinu. Typické vzory: Thread.sleep(), InputStream.read(), BinderProxy.transact(). Pro extrakci souboru ze zařízení použijte adb s právy superuživatele.
Firebase Crashlytics automaticky shromažďuje ANR a zobrazuje je na dashboardu spolu se stopováním. Pro Android 11+ přicházejí hlášení ANR s úplným zásobníkem hlavního vlákna. Integrace vyžaduje přidání závislosti a inicializaci FirebaseApp v Application.onCreate.
CPU Profiler v Android Studio umožňuje zaznamenat stopování činnosti aplikace a zjistit, které metody zabírají čas CPU. Zapněte „Record with method traces“ a reprodukujte scénář způsobující ANR. Na časové ose bude viditelné, které metody byly spouštěny v hlavním vlákně v okamžiku zamrznutí.
Příklad integrace Firebase Crashlytics pro sběr ANR na Androidu:
class App : Application() {
override fun onCreate() {
super.onCreate()
FirebaseApp.initializeApp(this)
FirebaseCrashlytics.getInstance()
.setCrashlyticsCollectionEnabled(true)
StrictMode.setThreadPolicy(StrictMode.ThreadPolicy.Builder()
.detectAll()
.penaltyLog()
.build())
}
}
Odstranění ANR znamená především přesun všech dlouhých operací z hlavního vlákna do vláken na pozadí. Podívejme se na konkrétní techniky pro každý typ komponenty.
WorkManager — doporučené řešení od Google pro práci na pozadí. Zaručuje provedení úlohy ve vlákně na pozadí s ohledem na stav zařízení. Na rozdíl od Service WorkManager neblokuje hlavní vlákno a je odolný vůči restartu aplikace. Pro BroadcastReceiver použijte goAsync() a předejte výsledek PendingResult do WorkManager.
Spouštějte všechny síťové požadavky, práci s databází a operace se soubory s Dispatchers.IO. Hlavní vlákno by mělo pouze aktualizovat UI. Použijte viewModelScope pro automatické zrušení korutin při zničení Activity. Vyhněte se runBlocking() v jakémkoli kontextu — to je synchronní blokování aktuálního vlákna.
Pokud ContentProvider provádí dlouhou inicializaci, použijte mechanismus odloženého načítání: vytvořte poskytovatele, který okamžitě vrací data, a těžkou inicializaci spusťte prostřednictvím WorkManager se zpožděním. Tím se zabrání ANR při spouštění aplikace, kdy je systém nejcitlivější na zpoždění.
Příklad správného použití BroadcastReceiver s goAsync v Androidu:
class FcmReceiver : BroadcastReceiver() {
override fun onReceive(context: Context?, intent: Intent?) {
val pendingResult = goAsync()
WorkManager.getInstance(context!!)
.enqueue(OneTimeWorkRequest.from(NotificationWorker::class.java))
pendingResult.finish()
}
}
Nejlepší způsob boje proti ANR je předcházet jejich vzniku ve fázi vývoje pomocí nástrojů a architektonických řešení.
StrictMode s aktivovanými politikami detectNetwork() a detectDiskReads()/detectDiskWrites() odhaluje potenciální ANR ve fázi vývoje. V sestavení Debug nastavte penaltyDeath — jakékoli porušení povede k okamžitému pádu a vývojář uvidí problém před potvrzením změn.
Firebase Performance sleduje dobu provádění klíčových operací a ukazuje, které scénáře překračují práh ANR. Nakonfigurujte vlastní stopování pro každou obrazovku a síťový požadavek. Pokud doba provádění přesáhne 3 sekundy — jedná se o potenciální ANR vyžadující optimalizaci.
Simulujte pomalé podmínky: omezte rychlost sítě pomocí Network Link Conditioner na iOS nebo Android Emulator. Zpomalte čtení z disku pomocí emulace pomalé paměti. ANR se často objevuje právě za takových podmínek, na rychlých zařízeních vývojáře není viditelný.
Často kladené otázky
Android explicitně sleduje dobu zpracování událostí v hlavním vlákně a zobrazuje dialog ANR. iOS používá Watchdog, který při zamrznutí delším než 10–20 sekund vynutí uzavření aplikace. ANR je vlastnost architektury Androidu, kde několik komponent (BroadcastReceiver, Service) má přísné časové limity.
Na Android 11+ můžete získat výpis ANR pomocí adb shell dumpsys dropbox --print data_app_anr. Na Android 10 a nižším bez rootu není přístup k /data/anr/traces.txt. Použijte Firebase Crashlytics — automaticky shromažďuje hlášení ANR pro Android 11+.
Google Play doporučuje míru ANR nižší než 0,5 % — tedy ne více než 5 ANR na 1000 relací. Aplikace s mírou nad 1 % obdrží varování v konzoli Google Play Console a může být skryta z doporučení. Ideálně by míra ANR měla být pod 0,1 %.
Korutina sama o sobě neblokuje vlákno. Ale pokud je uvnitř korutiny spuštěno runBlocking v hlavním vlákně nebo je korutina spuštěna s Dispatchers.Main a provádí dlouhou operaci CPU — způsobí to ANR. Používejte Dispatchers.IO pro vstup-výstup a Dispatchers.Default pro výpočty.
Použijte Android Emulator s profilem „Slow Network“ nebo napište test, který volá Thread.sleep(6000) v hlavním vlákně. Spusťte aplikaci přes Debug a po 5 sekundách uvidíte dialog ANR. Zkontrolujte, že se v logcat objevil záznam ANR se stopováním.
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é