ANR (Application Not Responding) — to systemowe powiadomienie Androida, które pojawia się, gdy aplikacja przestaje reagować na wprowadzane przez użytkownika dane na dłużej niż 5 sekund. Według Android Developers, główną przyczyną są długotrwałe operacje na głównym wątku, blokujące przetwarzanie dotknięć i renderowanie interfejsu. Zrozumienie mechanizmów ANR jest niezbędne dla każdego programisty Androida, aby tworzyć responsywne aplikacje.
Najważniejsze
ANR (Application Not Responding) — to okno dialogowe systemu operacyjnego Android, które pojawia się, gdy aplikacja przestaje odpowiadać na wprowadzane przez użytkownika dane. System śledzi czas przetwarzania zdarzeń przez InputDispatcher: jeśli dotknięcie lub naciśnięcie przycisku nie zostanie obsłużone w ciągu 5 sekund, Android wyświetla dialog z propozycją zamknięcia lub poczekania na aplikację.
Mechanizm ANR chroni doświadczenie użytkownika przed zawieszonymi aplikacjami. Android nie pozwala jednej aplikacji blokować całego systemu — w przeciwieństwie do systemów Desktop, platforma mobilna wymusza ograniczenie czasu przetwarzania zdarzeń. BroadcastReceiver ma limit 10 sekund, a usługa foreground — 20 sekund.
ANR NIE jest wyjątkiem w kodzie — to mechanizm systemowy na poziomie procesów Linuxa. Android wysyła sygnał SIGQUIT do procesu, po czym system zapisuje stos wywołań wszystkich wątków do pliku traces.txt. Programista otrzymuje ANR nie jako catch-wyjątek, ale jako raport po restarcie aplikacji. Na Androidzie 11+ pojawiło się API ApplicationExitInfo, które pozwala programowo uzyskać przyczynę zakończenia procesu, w tym ANR — upraszcza to zbieranie statystyk bez ręcznego parsowania traces.txt.
Pięć kategorii operacji stabilnie prowadzi do ANR w aplikacjach Android. Każda z nich blokuje główny wątek, uniemożliwiając systemowi przetwarzanie zdarzeń wejściowych i przerysowywanie ekranu.
Synchroniczne żądania HTTP wykonane na wątku UI — najczęstsza przyczyna ANR u początkujących programistów. Nawet szybkie żądanie do serwera może zająć 1–3 sekundy, a przy słabym połączeniu — 30 sekund i więcej. Android jawnie zabrania operacji sieciowych na głównym wątku od API 11, wyrzucając NetworkOnMainThreadException.
Używaj Coroutines lub RxJava do asynchronicznych wywołań. Korutyny z dyspozytorem Dispatchers.IO wykonują żądanie w tle, a wynik przekazują na główny przez Dispatchers.Main. To całkowicie eliminuje blokowanie wątku UI przez operacje sieciowe.
fun fetchUserData() {
CoroutineScope(Dispatchers.Main).launch {
val result = withContext(Dispatchers.IO) {
api.getUserData() // operacja w tle
}
updateUI(result) // wynik na głównym wątku
}
}
Przetwarzanie dużych tablic danych, parsowanie JSON lub XML, praca z bitmapami bezpośrednio na głównym wątku — druga pod względem częstotliwości przyczyna ANR. Nawet 300 milisekund ciągłej pracy wątku UI bez powrotu do pętli zdarzeń powoduje zauważalne opóźnienie renderowania, a wartość graniczna 5 sekund jest rejestrowana jako ANR.
WorkManager i usługi tła są przeznaczone do przenoszenia ciężkich obliczeń z głównego wątku. Używaj AsyncTask (przestarzałe), ListenableFuture lub Kotlin Flow do przesyłania danych porcjami, nie blokując UI.
Deadlock występuje, gdy dwa wątki trzymają blokady i czekają na siebie nawzajem. Jeśli jeden z wątków jest głównym, system rejestruje ANR dokładnie po 5 sekundach. Thread.join(), CountDownLatch.await() i blokady synchronized wywoływane z wątku UI niosą ryzyko blokady.
Unikaj wszelkich blokujących operacji na głównym wątku. Zamiast synchronized używaj ConcurrentHashMap, zamiast Thread.join() — korutyn z async/await. Ta zasada obowiązuje dla każdego języka w Androidzie: Java, Kotlin lub C++ przez JNI.
BroadcastReceiver domyślnie wykonuje się na głównym wątku. Jeśli onReceive() jest zajęty dłużej niż 10 sekund, Android wyświetla ANR. Ładowanie danych z bazy danych lub sieci wewnątrz onReceive to gwarantowana droga do zawieszenia.
Używaj goAsync() wewnątrz BroadcastReceiver do przełączenia na wątek tła albo registerReceiver z getBackgroundBroadcastReceiver(). Pozwala to na przetwarzanie zdarzeń bez blokowania UI.
Ciężkie zapytania do ContentProvider lub bezpośrednia praca z SQLite na wątku UI — mniej oczywista, ale częsta przyczyna ANR. Podczas migracji bazy danych lub wsadowego wstawiania tysięcy rekordów czas wykonania może przekroczyć 5-sekundowy limit.
Przenoś wszystkie operacje na bazie danych do wątków tła przez Room z suspend-funkcjami. Room automatycznie sprawdza, czy zapytanie nie jest wykonywane na głównym wątku i wyrzuca wyjątek w przypadku naruszenia.
Diagnozowanie ANR różni się od debugowania zwykłych wyjątków — nie można złapać ANR w try-catch. Głównym źródłem informacji jest plik traces.txt, który Android tworzy w momencie zawieszenia.
traces.txt zawiera stos wywołań wszystkich wątków aplikacji w momencie ANR. Aby odczytać plik z rzeczywistego urządzenia, wykonaj polecenie adb bugreport, które zbiera pełny raport systemu, w tym wszystkie ANR z ostatniego czasu. Dla emulatora plik jest dostępny w /data/anr/traces.txt. Stos wywołań pokazuje, która metoda wykonywała się na głównym wątku w momencie blokady.
adb bugreport bugreport.zip
unzip -p bugreport.zip "*traces*" > traces.txt
Google Play Console udostępnia sekcję ANR & Crash z zagregowanymi raportami i częstotliwościami błędów. Dla każdego ANR pokazany jest stos wywołań i statystyki według urządzeń: model, wersja Androida, region. Pozwala to zidentyfikować ANR, które zależą od konkretnych urządzeń lub wersji systemu.
Android Studio od 2021 roku zawiera ANR Watchdog w profilatorze. Automatycznie zapisuje zrzut wątków, jeśli główny wątek nie odpowiada dłużej niż progowy czas. Narzędzie pokazuje oś czasu zdarzeń: jakie operacje były uruchamiane, jakie metody były wykonywane i na którym etapie nastąpiła blokada.
Profilaktyka ANR opiera się na jednej fundamentalnej zasadzie: główny wątek powinien tylko obsługiwać zdarzenia UI. Każda operacja trwająca dłużej niż 16 milisekund (czas jednej klatki) powinna być wykonywana w wątku tła.
StrictMode — wbudowane narzędzie Androida do wykrywania potencjalnych ANR na etapie rozwoju. Włącz je w Application.onCreate() z flagami dla operacji dyskowych i sieciowych. W przypadku naruszenia StrictMode wyrzuca wyjątek lub zapisuje w logcat.
if (BuildConfig.DEBUG) {
StrictMode.ThreadPolicy.Builder()
.detectDiskReads()
.detectDiskWrites()
.detectNetwork()
.penaltyLog()
.build()
.let { StrictMode.setThreadPolicy(it) }
}
Kotlin Coroutines — standardowy sposób asynchronicznej pracy w nowoczesnych aplikacjach Android. Główna zasada: operacje wejścia-wyjścia wykonują się na Dispatchers.IO, wynik przekazywany jest na Dispatchers.Main do aktualizacji UI. Dla scenariuszy Flow używaj Dispatchers.Default do zadań intensywnie obciążających CPU.
RxJava pozostaje popularny w projektach legacy. subscribeOn(Schedulers.io()) i observeOn(AndroidSchedulers.mainThread()) — minimalny zestaw do zapobiegania ANR. Główna zasada jest taka sama: żaden Observable ani Flowable nie powinien emitować danych z głównego wątku.
Firebase Crashlytics od wersji SDK 18.4.0 obsługuje monitorowanie ANR „od razu po wyjęciu z pudełka“. Dla Android 11+ Crashlytics używa systemowego API ApplicationExitInfo, które dostarcza dokładną przyczynę zakończenia: ANR, Crash lub zabicie przez system. Włącz niestandardowe klucze z parametrami ekranu i stanu dla kontekstowej analizy.
Pięć narzędzi pokrywa wszystkie etapy pracy z ANR: od debugowania na stacji roboczej po monitoring w produkcji. Każde narzędzie rozwiązuje swoje zadanie i dostarcza dane dla różnych scenariuszy.
| Narzędzie | Przeznaczenie | Format danych |
|---|---|---|
| StrictMode | Wykrywanie na etapie rozwoju | Logcat / Exception |
| ANR Watchdog (Android Studio) | Śledzenie w czasie rzeczywistym | Thread dump + timeline |
| Google Play Console | Zagregowana statystyka | ANR rate + stack traces |
| Firebase Crashlytics | Monitoring produkcyjny | ApplicationExitInfo |
| adb bugreport | Pełny raport systemowy | traces.txt + logcat + dmesg |
Każde narzędzie ma swoją niszę: StrictMode łapie oczywiste naruszenia na wczesnych etapach, Crashlytics pokazuje rzeczywistą częstotliwość ANR u użytkowników, a adb bugreport daje maksymalnie pełny obraz dla skomplikowanych przypadków. Łącz je dla pełnego pokrycia.
Firebase Performance śledzi czas odpowiedzi wątku UI i automatycznie tworzy ślady dla podejrzanie długich operacji. Jeśli główny wątek blokuje się na więcej niż 500 ms, Performance rejestruje niestandardowy ślad z nazwą metody-sprawcy. Pozwala to wykrywać scenariusze ANR bez udziału użytkownika i zanim staną się krytyczne.
Integracja z Firebase Crashlytics daje pełny obraz: Performance pokazuje spowolnienia przed ANR, a Crashlytics — sam fakt zawieszenia. Skonfiguruj alerty w Firebase Console na zdarzenie ANR rate powyżej 0.1%, a będziesz otrzymywać powiadomienia o nowych problemach zanim pojawią się masowe skargi użytkowników.
Często zadawane pytania
ANR — to zawieszenie, przy którym aplikacja nie odpowiada, ale pozostaje w pamięci. Crash — całkowite awaryjne zakończenie z wyjściem z procesu. ANR można „przeżyć“, jeśli system lub użytkownik poczekają na odpowiedź, a Crash zawsze kończy aplikację.
Nie. ANR — to nie wyjątek Java/Kotlin, a sygnał systemu na poziomie procesów (SIGQUIT). Programista nie może go obsłużyć w kodzie aplikacji. Jedynym sposobem reagowania na ANR jest analizowanie raportów po restarcie.
Wydajność urządzenia, wersja Androida, obciążenie CPU i liczba procesów tła wpływają na prawdopodobieństwo ANR. Na słabych urządzeniach ta sama operacja może wykonywać się 2–3 razy dłużej, przekraczając 5-sekundowy limit.
10 sekund dla zwykłego BroadcastReceiver w onReceive(). Dla usług foreground limit wynosi 20 sekund, a dla ContentProvider — nie ma wyraźnego limitu, ale blokada głównego wątku dłuższa niż 5 sekund i tak wywołuje ANR.
Włącz StrictMode we wszystkich debug-buildach, dodaj monitoring przez Firebase Crashlytics i używaj adb bugreport, gdy ANR wystąpi. Nieregularne ANR często są związane z warunkami wyścigu (race condition) lub specyficznymi stanami sieci.
Podsumowanie
Opracujemy aplikację mobilną pod klucz
IT Sectr tworzy aplikacje na iOS i Androida dla startupów i firm od 2017 roku. Doradzimy Ci i zaproponujemy najlepsze rozwiązanie.
Przeczytaj również