ANR (Application Not Responding) — este o notificare de sistem Android care apare atunci când aplicația nu răspunde la intrare timp de 5 secunde. Spre deosebire de glitch-uri (erori logice fără blocarea UI) și lag-uri (încetinire fără oprire completă), ANR este o defecțiune critică înregistrată de sistemul de operare: Android afișează dialogul „Aplicația nu răspunde” cu opțiunea de a închide sau aștepta. Conform Android Vitals Documentation, aplicațiile cu o rată ANR peste 0,5% au un rating scăzut în Google Play și pot fi ascunse din recomandări. Diagnosticul include analiza /data/anr/traces.txt, utilizarea StrictMode și profilarea thread-ului principal.
Principalele puncte
ANR (Application Not Responding) — este un mecanism de protecție a utilizatorului în Android care se activează atunci când aplicația încetează să răspundă la intrări. Sistemul urmărește timpul de procesare a evenimentelor: dacă BroadcastReceiver nu finalizează onReceive în 10 secunde, Service nu revine din onCreate în 20 de secunde, iar ContentProvider nu răspunde în 15 secunde — Android generează ANR.
Când apare ANR, Android afișează un dialog de sistem deasupra tuturor ferestrelor: „Aplicația nu răspunde. Doriți să o închideți sau să așteptați?”. Utilizatorul poate închide aplicația sau poate aștepta recuperarea acesteia. Dacă ANR se repetă frecvent, utilizatorul șterge aplicația. Google Play ia în considerare rata ANR — procentul sesiunilor cu ANR — în algoritmii de clasare.
Pe iOS nu există un echivalent al ANR cu dialog de sistem. În schimb, Apple folosește Watchdog, care termină procesul aplicației cu codul 0x8badf00d. Utilizatorul nu vede niciun dialog — aplicația se închide pur și simplu pe ecranul principal. Acest lucru face ca ANR pe Android să fie mai vizibil pentru utilizator, dar oferă sistemului mai multe informații pentru diagnostic.
ANR apare atunci când sistemul urmărește timeout-ul pentru unul dintre cele patru tipuri de componente. Fiecare componentă are propria limită de timp.
BroadcastReceiver se execută în thread-ul principal. Dacă onReceive lansează o cerere de rețea sincronă, o operație lungă de scriere în baza de date sau așteaptă o blocare — după 10 secunde apare ANR. Soluție: utilizați goAsync() și WorkManager pentru procesarea în fundal. Scenariu tipic — primirea unei notificări Push de la FCM și salvarea sincronă în Room.
Service.onCreate și Service.onStartCommand au o limită de 20 de secunde. Dacă serviciul lansează o inițializare grea (încărcarea bibliotecilor, citirea configurației din rețea) în thread-ul principal — ANR este inevitabil. Utilizați IntentService (învechit) sau WorkManager pentru execuția garantată în thread-ul de fundal.
ContentProvider.onCreate se execută înainte de apelul Application.onCreate și are o limită de 15 secunde. Dacă providerul execută migrarea bazei de date, încărcarea dicționarelor sau inițializarea SDK din rețea — acest lucru provoacă ANR la pornirea aplicației. Soluție: inițializare lazy, mutarea operațiilor grele în WorkManager.
Android oferă mai multe instrumente pentru analiza ANR: de la jurnale de sistem până la biblioteci specializate.
La fiecare ANR, Android salvează fișierul /data/anr/traces.txt cu dump-ul stivelor tuturor thread-urilor aplicației. Găsiți thread-ul „main” — ultima metodă din stivă indică cauza. Modele tipice: Thread.sleep(), InputStream.read(), BinderProxy.transact(). Pentru extragerea fișierului de pe dispozitiv, utilizați adb cu drepturi de superutilizator.
Firebase Crashlytics colectează automat ANR-urile și le afișează în dashboard împreună cu trasarea. Pentru Android 11+, rapoartele ANR vin cu stiva completă a thread-ului principal. Integrarea necesită adăugarea dependenței și inițializarea FirebaseApp în Application.onCreate.
CPU Profiler din Android Studio vă permite să înregistrați trasarea funcționării aplicației și să vedeți ce metode ocupă timp CPU. Activați „Record with method traces” și reproduceți scenariul care provoacă ANR. Pe axa temporală va fi vizibil ce metode se executau în thread-ul principal în momentul înghețării.
Exemplu de integrare Firebase Crashlytics pentru colectarea ANR pe Android:
class App : Application() {
override fun onCreate() {
super.onCreate()
FirebaseApp.initializeApp(this)
FirebaseCrashlytics.getInstance()
.setCrashlyticsCollectionEnabled(true)
StrictMode.setThreadPolicy(StrictMode.ThreadPolicy.Builder()
.detectAll()
.penaltyLog()
.build())
}
}
Remedierea ANR înseamnă în primul rând mutarea tuturor operațiilor lungi din thread-ul principal în cele de fundal. Să analizăm tehnicile specifice pentru fiecare tip de componentă.
WorkManager — soluția recomandată de Google pentru munca în fundal. Garantează execuția sarcinii în thread-ul de fundal ținând cont de starea dispozitivului. Spre deosebire de Service, WorkManager nu blochează thread-ul principal și este rezistent la repornirea aplicației. Pentru BroadcastReceiver, utilizați goAsync() și transmiteți rezultatul PendingResult către WorkManager.
Lansați toate cererile de rețea, lucrul cu baza de date și operațiile cu fișiere cu Dispatchers.IO. Thread-ul principal ar trebui să actualizeze doar UI. Utilizați viewModelScope pentru anularea automată a corutinelor la distrugerea Activity. Evitați runBlocking() în orice context — aceasta este o blocare sincronă a thread-ului curent.
Dacă ContentProvider execută o inițializare lungă, utilizați mecanismul de încărcare întârziată: creați un provider care returnează datele imediat, iar inițializarea grea lansați-o prin WorkManager cu întârziere. Aceasta previne ANR la pornirea aplicației, când sistemul este cel mai sensibil la întârzieri.
Exemplu de utilizare corectă a BroadcastReceiver cu goAsync în 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()
}
}
Cea mai bună modalitate de a lupta cu ANR este prevenirea apariției lor în faza de dezvoltare prin instrumente și soluții arhitecturale.
StrictMode cu politicile detectNetwork() și detectDiskReads()/detectDiskWrites() activate detectează potențialele ANR în faza de dezvoltare. În compilarea Debug, setați penaltyDeath — orice încălcare va duce la o cădere imediată, iar dezvoltatorul va vedea problema înainte de commit.
Firebase Performance urmărește timpul de execuție al operațiilor cheie și arată care scenarii depășesc pragul ANR. Configurați trasări personalizate pentru fiecare ecran și cerere de rețea. Dacă timpul de execuție depășește 3 secunde — acesta este un ANR potențial care necesită optimizare.
Simulați condiții lente: limitați viteza rețelei prin Network Link Conditioner pe iOS sau Android Emulator. Încetiniți citirea de pe disc prin emularea memoriei lente. ANR apare adesea tocmai în astfel de condiții, pe dispozitivele rapide ale dezvoltatorului nefiind vizibile.
Întrebări frecvente
Android urmărește explicit timpul de procesare a evenimentelor pe thread-ul principal și afișează dialogul ANR. iOS folosește Watchdog, care închide forțat aplicația după înghețare de peste 10–20 de secunde. ANR este o caracteristică a arhitecturii Android, unde mai multe componente (BroadcastReceiver, Service) au timeout-uri stricte.
Pe Android 11+ puteți obține dump-ul ANR prin adb shell dumpsys dropbox --print data_app_anr. Pe Android 10 și mai jos, fără root, nu există acces la /data/anr/traces.txt. Utilizați Firebase Crashlytics — colectează automat rapoartele ANR pentru Android 11+.
Google Play recomandă o rată ANR sub 0,5% — adică nu mai mult de 5 ANR la 1000 de sesiuni. O aplicație cu o rată peste 1% primește un avertisment în Google Play Console și poate fi ascunsă din recomandări. În mod ideal, rata ANR ar trebui să fie sub 0,1%.
Corutina în sine nu blochează thread-ul. Dar dacă în interiorul corutinei se execută runBlocking pe thread-ul principal sau corutina este lansată cu Dispatchers.Main și execută o operație CPU lungă — aceasta va provoca ANR. Utilizați Dispatchers.IO pentru intrare-ieșire și Dispatchers.Default pentru calcule.
Utilizați Android Emulator cu profilul „Slow Network” sau scrieți un test care apelează Thread.sleep(6000) pe thread-ul principal. Lansați aplicația prin Debug și după 5 secunde veți vedea dialogul ANR. Verificați că în logcat a apărut o înregistrare ANR cu trasare.
Concluzii
Vom dezvolta o aplicație mobilă la cheie
IT Sectr creează aplicații iOS și Android pentru startup-uri și afaceri din 2017. Vă vom consilia și vă vom propune cea mai bună soluție.
Citiți și