ANR (Application Not Responding) — egy Android rendszerértesítés, amely akkor jelenik meg, amikor az alkalmazás 5 másodpercig nem reagál a bevitelre. Ellentétben a glitchekkel (logikai hibák a UI blokkolása nélkül) és lagekkel (lassulás teljes leállás nélkül), az ANR egy kritikus hiba, amelyet az operációs rendszer rögzít: az Android megjeleníti az „Alkalmazás nem válaszol” párbeszédablakot a bezárás vagy várakozás lehetőségével. A Android Vitals Documentation szerint a 0,5% feletti ANR-aránnyal rendelkező alkalmazások alacsonyabb értékelést kapnak a Google Play-ben, és elrejthetők az ajánlásokból. A diagnosztika magában foglalja a /data/anr/traces.txt elemzését, a StrictMode használatát és a fő szál profilozását.
Főbb pontok
ANR (Application Not Responding) — egy felhasználóvédelmi mechanizmus Androidon, amely akkor aktiválódik, amikor az alkalmazás leáll a bevitelre való reagálással. A rendszer nyomon követi az események feldolgozási idejét: ha a BroadcastReceiver nem fejezi be az onReceive-t 10 másodpercen belül, a Service nem tér vissza az onCreate-ből 20 másodpercen belül, és a ContentProvider nem válaszol 15 másodpercen belül — az Android ANR-t generál.
Amikor ANR történik, az Android egy rendszer-párbeszédablakot jelenít meg az összes ablak fölött: „Az alkalmazás nem válaszol. Bezárja vagy vár?”. A felhasználó bezárhatja az alkalmazást, vagy várhat a helyreállására. Ha az ANR gyakran ismétlődik, a felhasználó törli az alkalmazást. A Google Play figyelembe veszi az ANR-arányt — az ANR-rel rendelkező munkamenetek százalékát — a rangsorolási algoritmusokban.
Az iOS-en nincs az ANR-nek megfelelő rendszer-párbeszédablakos megoldás. Ehelyett az Apple Watchdog-ot használ, amely 0x8badf00d kóddal fejezi be az alkalmazás folyamatát. A felhasználó nem lát párbeszédablakot — az alkalmazás egyszerűen bezáródik a főképernyőre. Ez az ANR-t Androidon jobban láthatóvá teszi a felhasználó számára, de több információt ad a rendszernek a diagnosztikához.
Az ANR akkor következik be, amikor a rendszer időtúllépést figyel a négy komponenstípus egyikénél. Minden komponensnek saját időkorlátja van.
BroadcastReceiver a fő szálon fut. Ha az onReceive szinkron hálózati kérést, hosszú adatbázis-írási műveletet indít, vagy blokkolásra vár — 10 másodperc után ANR lép fel. Megoldás: használjon goAsync()-t és WorkManager-t a háttérfeldolgozáshoz. Tipikus forgatókönyv — Push-értesítés fogadása az FCM-től és szinkron mentés a Room-ba.
Service.onCreate és Service.onStartCommand 20 másodperces korláttal rendelkezik. Ha a szolgáltatás nehéz inicializálást (könyvtárak betöltése, konfiguráció olvasása a hálózatról) indít a fő szálon — az ANR elkerülhetetlen. Használjon IntentService-t (elavult) vagy WorkManager-t a garantált háttérszálon történő végrehajtáshoz.
ContentProvider.onCreate az Application.onCreate meghívása előtt fut, és 15 másodperces korlátja van. Ha a provider adatbázis-migrációt, szótárak betöltését vagy SDK-inicializálást végez a hálózatról — ez ANR-t okoz az alkalmazás indításakor. Megoldás: lusta inicializálás, nehéz műveletek áthelyezése a WorkManager-be.
Az Android több eszközt kínál az ANR elemzéséhez: a rendszernaplóktól a speciális könyvtárakig.
Minden ANR-nél az Android elmenti a /data/anr/traces.txt fájlt az alkalmazás összes szálának veremkiírásával. Keresse meg a „main” szálat — a veremben lévő utolsó metódus jelzi az okot. Tipikus minták: Thread.sleep(), InputStream.read(), BinderProxy.transact(). A fájl eszközről történő kinyeréséhez használjon adb-t rendszergazdai jogosultságokkal.
Firebase Crashlytics automatikusan gyűjti az ANR-eket, és megjeleníti azokat a műszerfalon nyomkövetéssel együtt. Android 11+ esetén az ANR-jelentések a fő szál teljes vermével érkeznek. Az integrációhoz függőség hozzáadása és a FirebaseApp inicializálása szükséges az Application.onCreate-ben.
CPU Profiler az Android Studio-ban lehetővé teszi az alkalmazás működésének nyomkövetését, és annak megtekintését, hogy mely metódusok foglalják a CPU-időt. Kapcsolja be a „Record with method traces” opciót, és reprodukálja az ANR-t okozó forgatókönyvet. Az idővonalon látható lesz, hogy mely metódusok futottak a fő szálon a lefagyás pillanatában.
Példa a Firebase Crashlytics integrációjára ANR gyűjtéséhez Androidon:
class App : Application() {
override fun onCreate() {
super.onCreate()
FirebaseApp.initializeApp(this)
FirebaseCrashlytics.getInstance()
.setCrashlyticsCollectionEnabled(true)
StrictMode.setThreadPolicy(StrictMode.ThreadPolicy.Builder()
.detectAll()
.penaltyLog()
.build())
}
}
Az ANR elhárítása elsősorban az összes hosszú művelet áthelyezését jelenti a fő szálból a háttérszálakba. Tekintsük át a konkrét technikákat az egyes komponenstípusokhoz.
WorkManager — a Google által ajánlott megoldás háttérmunkához. Garantálja a feladat végrehajtását a háttérszálon, figyelembe véve az eszköz állapotát. A Service-szel ellentétben a WorkManager nem blokkolja a fő szálat, és ellenálló az alkalmazás újraindításával szemben. BroadcastReceiver esetén használjon goAsync()-t, és adja át az eredmény PendingResult-ot a WorkManager-nek.
Indítson minden hálózati kérést, adatbázis-műveletet és fájloperációt Dispatchers.IO-val. A fő szálnak csak a UI-t kell frissítenie. Használjon viewModelScope-t a coroutine-ok automatikus megszakításához az Activity megsemmisülésekor. Kerülje a runBlocking() használatát bármilyen kontextusban — ez az aktuális szál szinkron blokkolása.
Ha a ContentProvider hosszú inicializálást végez, használjon késleltetett betöltési mechanizmust: hozzon létre egy providert, amely azonnal visszaadja az adatokat, és a nehéz inicializálást indítsa el WorkManager-en keresztül késleltetéssel. Ez megakadályozza az ANR-t az alkalmazás indításakor, amikor a rendszer a legérzékenyebb a késleltetésekre.
Példa a BroadcastReceiver helyes használatára goAsync-val Androidon:
class FcmReceiver : BroadcastReceiver() {
override fun onReceive(context: Context?, intent: Intent?) {
val pendingResult = goAsync()
WorkManager.getInstance(context!!)
.enqueue(OneTimeWorkRequest.from(NotificationWorker::class.java))
pendingResult.finish()
}
}
A legjobb mód az ANR elleni küzdelemre az, ha megelőzzük azok megjelenését a fejlesztési szakaszban eszközök és architekturális megoldások segítségével.
StrictMode a detectNetwork() és detectDiskReads()/detectDiskWrites() szabályzatok bekapcsolásával felismeri a potenciális ANR-eket a fejlesztési szakaszban. Debug buildben állítsa be a penaltyDeath-ot — bármely megsértés azonnali összeomláshoz vezet, és a fejlesztő látja a problémát a commit előtt.
Firebase Performance nyomon követi a kulcsfontosságú műveletek végrehajtási idejét, és megmutatja, mely forgatókönyvek lépik túl az ANR-küszöböt. Állítson be egyéni nyomkövetéseket minden képernyőhöz és hálózati kéréshez. Ha a végrehajtási idő meghaladja a 3 másodpercet — ez egy potenciális ANR, amely optimalizálást igényel.
Szimuláljon lassú körülményeket: korlátozza a hálózati sebességet a Network Link Conditioner segítségével iOS-en vagy Android Emulatoron. Lassítsa a lemezről való olvasást lassú memória emulációjával. ANR gyakran pont ilyen körülmények között jelentkezik, a fejlesztő gyors eszközein nem látható.
Gyakran Ismételt Kérdések
Android kifejezetten nyomon követi az események feldolgozási idejét a fő szálon, és megjeleníti az ANR párbeszédablakot. Az iOS Watchdog-ot használ, amely 10–20 másodpercnél hosszabb lefagyás esetén kényszeríti az alkalmazás bezárását. Az ANR az Android architektúra sajátossága, ahol több komponensnek (BroadcastReceiver, Service) szigorú időtúllépései vannak.
Android 11+ esetén ANR-kiírást kaphat a adb shell dumpsys dropbox --print data_app_anr paranccsal. Android 10 és alatta root nélkül nincs hozzáférés a /data/anr/traces.txt fájlhoz. Használja a Firebase Crashlytics-t — automatikusan gyűjti az ANR-jelentéseket Android 11+ esetén.
A Google Play 0,5% alatti ANR-arányt ajánl — vagyis legfeljebb 5 ANR 1000 munkamenetenként. Az 1% feletti aránnyal rendelkező alkalmazás figyelmeztetést kap a Google Play Console-ban, és elrejthető az ajánlásokból. Ideális esetben az ANR-aránynak 0,1% alatt kell lennie.
A coroutine önmagában nem blokkolja a szálat. De ha a coroutine-on belül runBlocking fut a fő szálon, vagy a coroutine Dispatchers.Main-nel van indítva és hosszú CPU-műveletet hajt végre — ez ANR-t okoz. Használjon Dispatchers.IO-t bemenet-kimenethez és Dispatchers.Default-ot számításokhoz.
Használjon Android Emulator-t „Slow Network” profillal, vagy írjon egy tesztet, amely Thread.sleep(6000)-et hív a fő szálon. Indítsa el az alkalmazást Debug módban, és 5 másodperc múlva látni fogja az ANR párbeszédablakot. Ellenőrizze, hogy a logcat-ben megjelent-e egy ANR-bejegyzés nyomkövetéssel.
Összefoglalás
Kulcsrakész mobilalkalmazást fejlesztünk
Az IT Sectr 2017 óta készít iOS és Android alkalmazásokat induló vállalkozásoknak és vállalkozásoknak. Tanácsot adunk, és a legjobb megoldást javasoljuk.
Olvassa el is