ANR (Application Not Responding) — is een systeemmelding van Android die verschijnt wanneer een app gedurende 5 seconden niet reageert op invoer. In tegenstelling tot glitches (logische fouten zonder UI-blokkering) en lag (vertraging zonder volledige stop), is ANR een kritieke fout die door het besturingssysteem wordt geregistreerd: Android toont een dialoogvenster "App reageert niet" met de optie om te sluiten of te wachten. Volgens Android Vitals Documentation hebben apps met een ANR-percentage boven 0,5% een lagere beoordeling in Google Play en kunnen ze worden verborgen in aanbevelingen. Diagnose omvat analyse van /data/anr/traces.txt, gebruik van StrictMode en profilering van de hoofdthread.
Belangrijkste punten
ANR (Application Not Responding) — is een gebruikersbeschermingsmechanisme in Android dat wordt geactiveerd wanneer een app stopt met reageren op invoer. Het systeem houdt de verwerkingstijd van gebeurtenissen bij: als BroadcastReceiver onReceive niet binnen 10 seconden voltooit, Service niet terugkeert van onCreate binnen 20 seconden, en ContentProvider niet reageert binnen 15 seconden — genereert Android een ANR.
Wanneer ANR optreedt, toont Android een systeemdialoogvenster boven alle vensters: "App reageert niet. Sluiten of wachten?". De gebruiker kan de app sluiten of wachten op herstel. Als ANR vaak voorkomt, verwijdert de gebruiker de app. Google Play houdt rekening met het ANR-percentage — het percentage sessies met ANR — in de rangschikkingsalgoritmen.
Op iOS bestaat geen equivalent van ANR met een systeemdialoogvenster. In plaats daarvan gebruikt Apple Watchdog, dat het app-proces beëindigt met code 0x8badf00d. De gebruiker ziet geen dialoogvenster — de app wordt gewoon naar het startscherm gesloten. Dit maakt ANR op Android zichtbaarder voor de gebruiker, maar geeft het systeem meer informatie voor diagnose.
ANR treedt op wanneer het systeem een time-out bijhoudt voor een van de vier componenttypen. Elk onderdeel heeft zijn eigen tijdslimiet.
BroadcastReceiver wordt uitgevoerd in de hoofdthread. Als onReceive een synchroon netwerkverzoek, een lange schrijfbewerking naar de database of wachten op een blokkering start — treedt na 10 seconden ANR op. Oplossing: gebruik goAsync() en WorkManager voor verwerking op de achtergrond. Typisch scenario — ontvangen van een Push-melding van FCM en synchroon opslaan in Room.
Service.onCreate en Service.onStartCommand hebben een limiet van 20 seconden. Als de service een zware initialisatie start (laden van bibliotheken, lezen van configuratie uit het netwerk) in de hoofdthread — is ANR onvermijdelijk. Gebruik IntentService (verouderd) of WorkManager voor gegarandeerde uitvoering in een achtergrondthread.
ContentProvider.onCreate wordt uitgevoerd vóór de aanroep van Application.onCreate en heeft een limiet van 15 seconden. Als de provider databasemigratie, het laden van woordenboeken of SDK-initialisatie via het netwerk uitvoert — veroorzaakt dit ANR bij het starten van de app. Oplossing: lazy-initialisatie, zware operaties verplaatsen naar WorkManager.
Android biedt verschillende hulpmiddelen voor ANR-analyse: van systeemlogs tot gespecialiseerde bibliotheken.
Bij elke ANR slaat Android het bestand /data/anr/traces.txt op met een dump van de stacks van alle threads van de app. Zoek de thread "main" — de laatste methode in de stack geeft de oorzaak aan. Typische patronen: Thread.sleep(), InputStream.read(), BinderProxy.transact(). Gebruik adb met supergebruikersrechten om het bestand van het apparaat te halen.
Firebase Crashlytics verzamelt automatisch ANR's en toont ze in het dashboard samen met tracering. Voor Android 11+ komen ANR-rapporten met de volledige stack van de hoofdthread. Integratie vereist het toevoegen van een afhankelijkheid en initialisatie van FirebaseApp in Application.onCreate.
CPU Profiler in Android Studio stelt u in staat een tracering van de app-werking vast te leggen en te zien welke methoden CPU-tijd in beslag nemen. Schakel "Record with method traces" in en reproduceer het scenario dat ANR veroorzaakt. Op de tijdlijn is te zien welke methoden op het moment van vastlopen in de hoofdthread werden uitgevoerd.
Voorbeeld van Firebase Crashlytics-integratie voor het verzamelen van ANR op Android:
class App : Application() {
override fun onCreate() {
super.onCreate()
FirebaseApp.initializeApp(this)
FirebaseCrashlytics.getInstance()
.setCrashlyticsCollectionEnabled(true)
StrictMode.setThreadPolicy(StrictMode.ThreadPolicy.Builder()
.detectAll()
.penaltyLog()
.build())
}
}
Het verhelpen van ANR betekent vooral het verplaatsen van alle lange operaties van de hoofdthread naar achtergrondthreads. Laten we de specifieke technieken voor elk componenttype bekijken.
WorkManager — de door Google aanbevolen oplossing voor achtergrondwerk. Het garandeert uitvoering van de taak in een achtergrondthread, rekening houdend met de apparaatstatus. In tegenstelling tot Service blokkeert WorkManager de hoofdthread niet en is het bestand tegen herstarten van de app. Gebruik voor BroadcastReceiver goAsync() en geef het resultaat PendingResult door aan WorkManager.
Start alle netwerkverzoeken, databasewerk en bestandsbewerkingen met Dispatchers.IO. De hoofdthread mag alleen de UI bijwerken. Gebruik viewModelScope voor automatische annulering van coroutines bij vernietiging van Activity. Vermijd runBlocking() in elke context — dit is een synchrone blokkering van de huidige thread.
Als ContentProvider een lange initialisatie uitvoert, gebruik dan een mechanisme voor uitgesteld laden: maak een provider die onmiddellijk gegevens retourneert en start de zware initialisatie via WorkManager met vertraging. Dit voorkomt ANR bij het starten van de app, wanneer het systeem het meest gevoelig is voor vertragingen.
Voorbeeld van correct gebruik van BroadcastReceiver met goAsync in 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()
}
}
De beste manier om ANR te bestrijden is voorkomen dat ze ontstaan in de ontwikkelingsfase door middel van tools en architectuuroplossingen.
StrictMode met ingeschakelde detectNetwork()- en detectDiskReads()/detectDiskWrites()-beleidsregels detecteert potentiële ANR's in de ontwikkelingsfase. Stel in Debug-build penaltyDeath in — elke overtreding leidt tot een onmiddellijke crash en de ontwikkelaar ziet het probleem vóór de commit.
Firebase Performance houdt de uitvoeringstijd van kritieke bewerkingen bij en toont welke scenario's de ANR-drempel overschrijden. Stel aangepaste traceringen in voor elk scherm en netwerkverzoek. Als de uitvoeringstijd 3 seconden overschrijdt — is dit een potentiële ANR die optimalisatie vereist.
Simuleer trage omstandigheden: beperk de netwerksnelheid via Network Link Conditioner op iOS of Android Emulator. Vertraag het lezen van de schijf door emulatie van traag geheugen. ANR verschijnt vaak juist onder dergelijke omstandigheden; op snelle ontwikkelaarsapparaten zijn ze niet zichtbaar.
Veelgestelde vragen
Android houdt expliciet de verwerkingstijd van gebeurtenissen op de hoofdthread bij en toont het ANR-dialoogvenster. iOS gebruikt Watchdog, dat de app geforceerd sluit bij vastlopen langer dan 10–20 seconden. ANR is een kenmerk van de Android-architectuur, waarbij meerdere componenten (BroadcastReceiver, Service) strikte time-outs hebben.
Op Android 11+ kunt u een ANR-dump verkrijgen via adb shell dumpsys dropbox --print data_app_anr. Op Android 10 en lager is er zonder root geen toegang tot /data/anr/traces.txt. Gebruik Firebase Crashlytics — het verzamelt automatisch ANR-rapporten voor Android 11+.
Google Play beveelt een ANR-percentage onder 0,5% aan — dat wil zeggen niet meer dan 5 ANR per 1000 sessies. Een app met een percentage boven 1% krijgt een waarschuwing in Google Play Console en kan worden verborgen in aanbevelingen. Idealiter zou het ANR-percentage onder 0,1% moeten liggen.
Een coroutine blokkeert op zichzelf de thread niet. Maar als binnen een coroutine runBlocking op de hoofdthread wordt uitgevoerd of de coroutine is gestart met Dispatchers.Main en een lange CPU-bewerking uitvoert — veroorzaakt dit ANR. Gebruik Dispatchers.IO voor invoer-uitvoer en Dispatchers.Default voor berekeningen.
Gebruik Android Emulator met het profiel "Slow Network" of schrijf een test die Thread.sleep(6000) aanroept op de hoofdthread. Start de app via Debug en na 5 seconden ziet u het ANR-dialoogvenster. Controleer of in logcat een ANR-registratie met tracering is verschenen.
Samenvatting
We ontwikkelen een mobiele applicatie turnkey
IT Sectr creëert sinds 2017 iOS- en Android-applicaties voor startups en bedrijven. We adviseren u en stellen de beste oplossing voor.
Lees ook