26/03/2023
Forestil dig, at du bruger din yndlingsapp på din Android-telefon. Pludselig fryser skærmen, og en dialogboks dukker op med beskeden 'Appen svarer ikke'. Dette er et klassisk eksempel på en ANR – Application Not Responding – fejl. Disse fejl er en af de mest frustrerende oplevelser for app-brugere og kan hurtigt føre til, at en app bliver afinstalleret. For udviklere er ANR'er et kritisk problem, der skal løses for at sikre en flydende og pålidelig brugeroplevelse. Men hvad er en ANR præcist, hvorfor opstår den, og hvordan kan vi effektivt forhindre dem? Denne artikel vil dykke ned i kernen af ANR-problematikken og give dig de nødvendige værktøjer og strategier til at holde dine Android-apps responsiv og velfungerende.

Hvad er en ANR?
ANR står for 'Application Not Responding' og indikerer en tilstand, hvor brugergrænsefladen (UI) i en Android-app bliver ikke-responsiv i en længere periode, typisk omkring fem sekunder. Når Android-systemet registrerer, at appens UI-tråd (også kendt som hovedtråden) ikke reagerer på brugerinput eller systembegivenheder, viser det en ANR-dialogboks til brugeren. Denne boks giver brugeren mulighed for enten at vente på, at appen svarer, eller at tvinge den til at lukke. En ANR er et alvorligt signal om, at appen ikke lever op til de forventninger, brugeren har til en flydende interaktion, og det kan have en direkte negativ indvirkning på appens omdømme og brugertilfredshed. Det er essentielt at forstå, at hovedtråden er ansvarlig for at håndtere alle brugerinteraktioner, opdatere skærmen og udføre hurtige opgaver. Hvis denne tråd bliver blokeret, kan appen ikke længere behandle input fra brugeren, hvilket fører til den frygtede ANR-fejl.
ANR vs. App-nedbrud: En Vigtig Forskel
Selvom både ANR'er og app-nedbrud resulterer i en negativ brugeroplevelse, er de fundamentalt forskellige i deres årsag og manifestation. Det er afgørende at kende forskellen for effektivt at diagnosticere og løse problemer. Et app-nedbrud opstår, når en undtagelse (exception) inden for appen kastes og ikke håndteres korrekt. Dette kan for eksempel være, hvis du forsøger at tilgå en null-reference, hvilket resulterer i en java.lang.NullPointerException. Når et nedbrud sker, lukker appen øjeblikkeligt ned, og brugeren får typisk en meddelelse om, at appen er lukket uventet, med en mulighed for at sende en fejlrapport. Brugeren vil ikke se, hvad der forårsagede nedbruddet, kun at appen stoppede med at fungere. En ANR derimod opstår, når hovedtråden er optaget med en langvarig operation. Appen lukker ikke ned automatisk; i stedet fryser den, og Android-systemet venter på, at hovedtråden igen bliver responsiv, før det præsenterer ANR-dialogboksen. Dette giver brugeren et valg, men signalerer stadig en alvorlig ydelsesproblematik.
| Karakteristik | ANR (Application Not Responding) | App-nedbrud (Crash) |
|---|---|---|
| Årsag | Hovedtråden er blokeret/optaget i længere tid (ca. 5 sekunder). | Ubehandlet undtagelse (exception) i koden. |
| Brugeroplevelse | App fryser, dialogboks "Appen svarer ikke" vises. Brugeren kan vælge at vente eller lukke. | App lukker øjeblikkeligt ned. Brugeren får besked om uventet lukning. |
| Eksempel | Udførelse af en kompleks sorteringsalgoritme på hovedtråden. | Forsøg på at tilgå en null-objekt (f.eks. NullPointerException). |
| Systemrespons | Systemet registrerer manglende respons og viser en advarsel. | Systemet afslutter appen pga. fejl. |
Almindelige Årsager til ANR'er
ANR'er kan udløses af en række faktorer, der alle har det til fælles, at de blokerer appens hovedtråd. At identificere de specifikke årsager er første skridt mod at løse problemet:
- Langvarige operationer på UI-tråden: At udføre tunge eller komplekse opgaver, såsom omfattende databaseforespørgsler, billedbehandling, eller komplekse beregninger, direkte på hovedtråden vil uundgåeligt blokere UI'en fra at reagere på brugerinput. Dette er den mest almindelige årsag til ANR'er.
- Netværksoperationer på UI-tråden: Blokerende netværkskald, især hvis netværket er langsomt eller ustabilt, kan forårsage ANR'er. Netværkskald bør altid udføres i baggrundstråde for at undgå at blokere hovedtråden.
- Holde WakeLocks for længe: Hvis en
WakeLockholdes for længe på UI-tråden, kan det forhindre enheden i at gå i lavenergitilstand, hvilket kan føre til ANR'er. WakeLocks skal håndteres omhyggeligt og frigives så hurtigt som muligt. - Deadlocks eller synkroniseringsproblemer: Komplekse trådinteraktioner, der fører til deadlocks eller problemer med trådsynkronisering, kan gøre UI-tråden uresponsiv, da den venter uendeligt på en ressource.
- Overdreven Garbage Collection: Hyppige og langvarige garbage collection-cyklusser kan sætte UI-tråden på pause, hvilket kan føre til en ANR, især på enheder med begrænsede ressourcer.
- Uendelige sløjfer eller tunge beregninger: Kører uendelige sløjfer eller ekstremt beregningstunge opgaver på hovedtråden, vil øjeblikkeligt blokere den og udløse en ANR.
- UI-tråden venter på eksterne ressourcer: Hvis hovedtråden venter på ressourcer fra eksterne kilder (f.eks. langsomme fil-I/O-operationer eller svar fra en server), og responsen tager for lang tid, kan det udløse en ANR.
- BroadcastReceiver og Service Timeout: Hvis en
BroadcastReceivereller enServiceikke fuldfører sin behandling inden for en specifik tidsramme (typisk 10 sekunder forBroadcastReceiverog 20 sekunder forServicei forgrunden, 200 sekunder forServicei baggrunden), kan det også føre til en ANR.
Sådan Forebygges ANR'er: Bedste Praksis
At forebygge ANR'er handler primært om at sikre, at hovedtråden altid er fri og responsiv. Dette opnås ved at flytte langvarige og blokerende operationer væk fra hovedtråden og over i baggrundstråde:
1. Brug Arbejdstråde (Worker Threads): Den vigtigste strategi er at udføre alle potentielt blokerende operationer på separate tråde. Android Framework tilbyder flere mekanismer til dette:
AsyncTask: (Selvom det er forældet i nyere API-niveauer, er det stadig relevant for ældre apps og som et koncept) Forenkler oprettelsen af baggrundsopgaver og publikation af resultater på UI-tråden.IntentService: Ideel til at udføre en enkelt baggrundsoperation og derefter automatisk stoppe sig selv. Den kører på en separat baggrundstråd.HandlerogLooper: Giver dig mulighed for at planlægge beskeder og runnables til at blive udført på en bestemt tråd, herunder oprettelse af dine egne baggrundstråde.- Standard Java
Thread: Du kan simpelthen oprette og starte en nyThreadfor at udføre en opgave i baggrunden. Husk dog at håndtere UI-opdateringer korrekt ved at poste dem tilbage til hovedtråden. - Kotlin Coroutines / Java Concurrency Utilities: For mere moderne Android-udvikling er Kotlin Coroutines eller Java's
ExecutorServiceogThreadPoolExecutorkraftfulde værktøjer til asynkron programmering og trådstyring.
2. Optimer Kode og Algoritmer: Gennemgå din kode for sårbare punkter og langvarige operationer. Overvej, om der er mere effektive algoritmer eller datastrukturer, der kan reducere den samlede udførelsestid. Undgå at bruge synkrone låse, Thread.sleep(), eller blokerende I/O-operationer på hovedtråden.
3. Håndtering af Netværkskald: Sørg for, at alle netværkskald er asynkrone og udføres på baggrundstråde. Biblioteker som Retrofit, OkHttp, eller Volley er designet til dette formål og tilbyder indbygget asynkronitet.

4. Effektiv Brug af BroadcastReceivers og Services: Sørg for, at dine BroadcastReceiver'e og Service's fuldfører deres arbejde inden for de tildelte tidsrammer. Hvis en BroadcastReceiver skal udføre en langvarig opgave, bør den delegere denne opgave til en IntentService eller en anden baggrundstråd.
5. Undgå Unødvendig UI-opdatering: Selvom UI-opdateringer skal ske på hovedtråden, kan for mange eller for komplekse opdateringer medføre ydelsesproblemer. Optimer dine layouts og undgå unødvendige invalideringer eller tegne-kald.
6. Android Vitals: Udnyt Android Vitals i Google Play Console. Dette værktøj overvåger din apps ydelse i den virkelige verden og advarer dig, hvis din app udviser for mange ANR'er. Android Vitals anser ANR'er for at være overdrevne, når en app:
- Udstiller mindst én ANR i mindst 0,47% af dens daglige sessioner.
- Udstiller 2 eller flere ANR'er i mindst 0,24% af dens daglige sessioner.
- Udstiller 3 eller flere ANR'er i mindst 0,17% af dens daglige sessioner.
Disse tærskler er vigtige at kende, da de definerer, hvornår Google Play begynder at nedprioritere din app i søgeresultater og anbefalinger.
Diagnosticering af ANR'er: Find og Løs Problemet
Selv med de bedste forebyggende foranstaltninger kan ANR'er stadig opstå. At diagnosticere dem effektivt er nøglen til hurtig løsning. Android tilbyder flere værktøjer og metoder til at spore årsagen til en ANR:
1. Forstå Hovedtrådens Aktivitet: En ANR opstår, når hovedtråden enten udfører en langsom operation, er i en deadlock, eller venter på en ekstern ressource. Typiske scenarier inkluderer:
- Appen udfører langsomme I/O-operationer (f.eks. læsning/skrivning til disk) på hovedtråden.
- Hovedtråden foretager et synkront binderkald til en anden proces, som tager lang tid at returnere.
- Hovedtråden er i en deadlock med en anden tråd, enten inden for din egen proces eller via et binderkald.
- Appen udfører en lang beregning på hovedtråden.
2. Brug Android StrictMode: Siden API Level 9 (Android 2.3 Gingerbread) kan du bruge StrictMode til at hjælpe med at opdage utilsigtede I/O-operationer og andre blokerende kald på hovedtråden under udviklingen. Du kan aktivere StrictMode på applikations- eller aktivitetsniveau for at få advarsler eller endda lade appen crashe, når uønskede operationer detekteres. Dette er et uvurderligt værktøj til tidlig detektion.
3. Analyser Trace-filer (traces.txt): Når en ANR opstår, opretter Android-systemet automatisk en trace-fil (typisk traces.txt eller lignende) i /data/anr/ mappen på enheden. Disse filer indeholder en snapshot af tilstanden for alle tråde i din app på det tidspunkt, hvor ANR'en skete. Du kan trække disse filer ud ved hjælp af ADB (Android Debug Bridge):
adb root adb shell ls /data/anr adb pull /data/anr/<filnavn>Gennemgangen af disse trace-filer kan afsløre, hvad hovedtråden (ofte navngivet "main" eller "UI") var i gang med, da ANR'en blev udløst. Kig efter tråde, der er i "RUNNABLE" tilstand og udfører komplekse metoder.

4. Android Device Monitor (DDMS): Selvom DDMS er blevet erstattet af mere moderne værktøjer i Android Studio, kan det stadig være nyttigt at inspicere tråde i realtid. Ved at aktivere trådvisningen kan du se status for alle tråde i din app. Hvis du reproducerer ANR'en og opdaterer trådvisningen på samme tid, kan du ofte se præcis, hvad der blokerer hovedtråden.
5. Firebase Crashlytics og Andre Overvågningsværktøjer: For apps i produktion er det essentielt at bruge overvågningsværktøjer som Firebase Crashlytics. Disse værktøjer kan automatisk fange ANR'er, logge deres frekvens, og give detaljerede stack traces, der viser, hvilken del af koden der forårsagede problemet, samt på hvilken tråd det skete. Dette giver dig et overblik over, hvilke ANR'er der påvirker flest brugere, og hvor i koden du skal fokusere din indsats.
Et Praktisk Eksempel på en ANR
Lad os betragte et simpelt kodeeksempel, der vil udløse en ANR:
public class MyActivity extends AppCompatActivity { // ... @Override public void onClick(View view) { // Denne opgave kører på hovedtråden // og vil forårsage en ANR, hvis 'data' er stor. MergeSort.sort(data); } // ... }I dette scenario udføres en potentielt tidskrævende sorteringsproces (MergeSort.sort(data)) direkte på hovedtråden som reaktion på et brugerklik. Hvis data-arrayet er stort, vil sorteringen tage mere end de kritiske fem sekunder, hvilket blokerer UI'en og fører til en ANR. Løsningen er at flytte denne sorteringsproces til en separat tråd:
public class MyActivity extends AppCompatActivity { // ... @Override public void onClick(View view) { new Thread(new Runnable() { @Override public void run() { // Denne opgave kører nu på en baggrundstråd MergeSort.sort(data); // Hvis du skal opdatere UI efter sortering, // brug en Handler eller runOnUiThread runOnUiThread(new Runnable() { @Override public void run() { // Opdater UI her } }); } }).start(); } // ... }Ved at indkapsle den tunge operation i en ny tråd, frigøres hovedtråden øjeblikkeligt til at håndtere brugerinput, hvilket eliminerer risikoen for en ANR forårsaget af denne specifikke opgave.
Ofte Stillede Spørgsmål (FAQ)
Her er svar på nogle af de mest almindelige spørgsmål vedrørende ANR'er:
- Q: Hvad er den primære forskel mellem en ANR og et nedbrud (crash)?
- A: En ANR opstår, når appens hovedtråd bliver uresponsiv i længere tid (ca. 5 sekunder), hvilket fører til, at systemet viser en "App svarer ikke"-dialog. Et nedbrud er derimod en ubehandlet fejl (exception) i koden, der får appen til øjeblikkeligt at lukke ned.
- Q: Hvorfor er ANR'er skadelige for brugeroplevelsen?
- A: ANR'er skaber en følelse af, at appen er frossen eller ødelagt. Dette er ekstremt frustrerende for brugeren, da de mister kontrol og interaktion med appen, hvilket ofte fører til afinstallation og en negativ anmeldelse.
- Q: Kan jeg altid forhindre ANR'er?
- A: Målet er at minimere dem drastisk. Ved at følge bedste praksis og udføre langvarige opgaver på baggrundstråde kan du næsten eliminere ANR'er forårsaget af din egen kode. Dog kan eksterne faktorer som dårlig netværksforbindelse eller enhedens ydelse stadig spille en rolle.
- Q: Hvad er Android StrictMode?
- A: StrictMode er et udviklerværktøj i Android, der hjælper med at identificere potentielle problemer i koden, såsom utilsigtet disk- eller netværks-I/O på hovedtråden. Det kan konfigureres til at logge advarsler, vise dialogbokse, eller endda crashe appen, når sådanne overtrædelser detekteres, hvilket hjælper med tidlig detektion under udviklingen.
- Q: Hvad er hovedtråden i Android?
- A: Hovedtråden, ofte kaldet UI-tråden, er den enkelttråd, der er ansvarlig for at håndtere alle brugergrænsefladeinteraktioner og opdateringer i en Android-app. Alle UI-komponenter og begivenheder kører på denne tråd, og det er afgørende, at den forbliver fri og responsiv for at undgå ANR'er.
Konklusion
ANR'er er en uundgåelig del af Android-udvikling, hvis ikke der tages de rette forholdsregler. De repræsenterer et alvorligt ydelsesproblem, der direkte påvirker brugeroplevelsen og appens succes. Ved at forstå, hvad en ANR er, hvorfor den opstår, og vigtigst af alt, hvordan man forebygger og diagnosticerer den, kan udviklere skabe mere stabile, responsiv og brugervenlige apps. Husk altid reglen: Ingen langvarige operationer på hovedtråden! Ved at delegere tunge opgaver til baggrundstråde og udnytte de mange værktøjer, Android-økosystemet stiller til rådighed, kan du sikre, at dine apps altid leverer en flydende og problemfri oplevelse til dine brugere.
Hvis du vil læse andre artikler, der ligner Undgå ANR'er: Hold Dine Android Apps Lynhurtige, kan du besøge kategorien Mobiludvikling.
