ANRs
On október 14, 2021 by adminHa egy Android-alkalmazás UI szála túl sokáig blokkolódik, “ApplicationNot Responding” (ANR) hiba lép fel. Ha az alkalmazás előtérben van, a rendszer az 1. ábrán látható párbeszédpanelt jeleníti meg a felhasználónak. Az ANR párbeszédpanel lehetőséget ad a felhasználónak az alkalmazás kényszerített kilépésére.
1. ábra. A felhasználónak megjelenített ANR párbeszédpanel
Az ANR-ek azért jelentenek problémát, mert az alkalmazás fő szála, amely a felhasználói felület frissítéséért felelős, nem tudja feldolgozni a felhasználói bemeneti eseményeket vagy rajzolni, ami frusztrációt okoz a felhasználónak. Az alkalmazás főszálával kapcsolatos további információkért lásd a Folyamatok és szálak című fejezetet.
Az ANR akkor lép működésbe az alkalmazásnál, ha az alábbi feltételek valamelyike bekövetkezik:
- Mialatt a tevékenység az előtérben van, az alkalmazás 5 másodpercen belül nem reagált egy beviteli eseményre vagy
BroadcastReceiver
(például billentyűleütés vagy képernyőérintés eseményre). - Míg nincs tevékenység az előtérben, a
BroadcastReceiver
nem fejezte be a végrehajtást számottevő időn belül.
Ha az alkalmazása ANR-eket tapasztal, a cikk útmutatásai alapján diagnosztizálhatja és orvosolhatja a problémát.
Problémák felismerése és diagnosztizálása
Az Android számos eszközt biztosít arra, hogy tudassa Önnel, ha az alkalmazásával probléma van, és segítsen a diagnosztizálásban.Ha már közzétette az alkalmazását, az Androidvitals figyelmeztetheti Önt a probléma megjelenésére, és vannak diagnosztikai eszközök, amelyek segítenek a probléma megtalálásában.
Androidvitals
Az Androidvitals segíthet javítani az alkalmazás teljesítményét azáltal, hogy a PlayConsole-on keresztül figyelmeztet, ha az alkalmazás túlzott ANR-t mutat.Az Android vitals akkor tekinti az ANR-eket túlzottnak, ha egy alkalmazás:
- a napi munkamenetek legalább 0,47%-ában legalább egy ANR-t mutat.
- a napi munkamenetek legalább 0,24%-ában 2 vagy több ANR-t mutat.
A napi munkamenet olyan napot jelent, amikor az alkalmazást használták.
Azzal kapcsolatban, hogy a Google Play hogyan gyűjti az Android életjeladatait, lásd a Play Console dokumentációját.
Az ANR-ek diagnosztizálása
Az ANR-ek diagnosztizálásakor néhány gyakori mintát kell keresni:
- Az alkalmazás lassú, I/O-t tartalmazó műveleteket végez a főszálon.
- Az alkalmazás hosszú számítást végez a főszálon.
- A főszál szinkron kötegelt hívást végez egy másik folyamathoz, és a másik folyamatnak sokáig tart a visszatérés.
- A főszál blokkolva vár egy szinkronizált blokkra egy hosszú művelethez, amely egy másik szálon történik.
- A főszál holtponton van egy másik szállal, akár a saját folyamatában, akár kötegelt híváson keresztül. A főszál nem csak egy hosszú művelet befejezésére vár, hanem holtponti helyzetben van. További információért lásd: Holtpont a Wikipédián.
A következő technikák segíthetnek kideríteni, hogy a fenti okok közül melyik okozza az ANR-eket.
Szigorú mód
A StrictMode
használata segít megtalálni a véletlen I/O műveleteket a főszálon az alkalmazás fejlesztése közben. A StrictMode
az alkalmazás vagy a tevékenység szintjén is használható.
Háttérben futó ANR párbeszédpanelek engedélyezése
Az Android csak akkor jeleníti meg az ANR párbeszédpaneleket azon alkalmazások számára, amelyeknek túl sokáig tart az adásüzenet feldolgozása, ha a készülék fejlesztői beállításaiban engedélyezve van az összes ANR megjelenítése. Emiatt a háttérben megjelenő ANR-dialógusok nem mindig jelennek meg a felhasználónak, de az alkalmazásnak ettől még lehetnek teljesítményproblémái.
Traceview
A Traceview segítségével nyomon követheti a futó alkalmazást, miközben végigjárja a felhasználási eseteket, és azonosíthatja azokat a helyeket, ahol a főszál elfoglalt. A Traceview használatával kapcsolatos információkért lásd: Profiling with Traceview anddmtracedump.
Pull a traces file
Az Android tárolja a nyomkövetési információkat, amikor ANR-t tapasztal. A régebbi OS-kiadásoknál egyetlen /data/anr/traces.txt
fájl van az eszközön.Az újabb OS-kiadásoknál több /data/anr/anr_*
fájl van.Hozzáférhet az ANR nyomvonalakhoz egy eszközről vagy emulátorból azAndroid Debug Bridge (adb) segítségével root felhasználóként:
adb rootadb shell ls /data/anradb pull /data/anr/<filename>
Hibajelentést rögzíthet egy fizikai eszközről a Take bugreport fejlesztői opcióval az eszközön, vagy az adb bugreport paranccsal a fejlesztőgépén. További információért lásd: Hibajelentések rögzítése és olvasása.
A problémák javítása
A probléma azonosítása után az ebben a szakaszban található tippek segítségével javíthatja a gyakran előforduló problémákat.
Lassú kód a főszálon
Identifikálja azokat a helyeket a kódjában, ahol az alkalmazás fő szála több mint 5 másodpercig foglalt. Keresse meg a gyanús felhasználási eseteket az alkalmazásában, és próbálja meg reprodukálni az ANR-t.
A 2. ábra például egy Traceview idővonalat mutat, ahol a főszál több mint 5 másodpercig elfoglalt.
2. ábra. Traceview idővonal, amely egy elfoglalt főszálat mutat
A 2. ábrán látható, hogy a legtöbb hibás kód a onClick(View)
kezelőben történik, amint az a következőkódpélda is mutatja:
Ez esetben a főszálban futó munkát át kell helyezni egy munkaszálba. Az Android Framework tartalmaz olyan osztályokat, amelyek segíthetnek a feladat áthelyezésében egy munkaszálba. További információkért lásd: Szálak kezelése az Androidon.
IO a főszálon
A főszálon végrehajtott IO műveletek gyakori oka a lassú műveleteknek a főszálon, ami ANR-eket okozhat. Ajánlott az összes IOműveletet egy munkaszálra áthelyezni, ahogyan az előző szakaszban látható.
Az IOműveletekre példaként említhetjük a hálózati és tárolási műveleteket. További információért lásd a Hálózati műveletek végrehajtása és az Adattárolás.
Lock contention
Egyes forgatókönyvekben az ANR-t okozó munka nem közvetlenül az alkalmazás fő szálán kerül végrehajtásra. Ha egy munkaszál zárat tart egy olyan erőforráson, amelyre a főszálnak szüksége van a munkája elvégzéséhez, akkor előfordulhat ANR.
A 4. ábra például egy olyan Traceview idővonalat mutat, ahol a munka nagy részét egy munkaszál végzi.
4. ábra. Traceview idővonal, amely a munkaszálon végrehajtott munkát mutatja
De ha a felhasználók továbbra is ANR-eket tapasztalnak, meg kell néznie a főszál állapotát az Android Device Monitorban. Általában a főszál aRUNNABLE
állapotban van, ha készen áll a felhasználói felület frissítésére, és általában reagál.
De ha a főszál nem tudja folytatni a végrehajtást, akkor a BLOCKED
állapotban van, és nem tud reagálni az eseményekre. A státusz az Android Device Monitoron Monitor vagy Wait néven jelenik meg, ahogy az 5. ábrán látható.
5. ábra. Főszál a Monitor állapotában
A következő nyomkövetés egy alkalmazás főszálát mutatja, amely blokkolva vár aresource-ra:
A nyomkövetés áttekintése segíthet megtalálni a főszálat blokkoló kódot.A következő kód felelős az előző nyomkövetésben a főszálat blokkoló zár tartásáért:
A másik példa egy alkalmazás főszála, amely egy eredményre vár egymunkásszáltól, ahogy az a következő kódban látható. Vegye figyelembe, hogy a wait()
ésnotify()
használata nem ajánlott minta a Kotlinban, amely saját mechanizmusokkal rendelkezik az egyidejűség kezelésére. Ha Kotlint használ, lehetőleg Kotlin-specifikus mechanizmusokat használjon.
Létezik néhány más helyzet is, amely blokkolhatja a főszálat, beleértve a Lock
, Semaphore
, valamint az erőforrás-poolt (például adatbázis-kapcsolatok poolját) vagy más kölcsönös kizárási (mutex) mechanizmusokat használó szálakat.
Az alkalmazás által az erőforrásokra tartott zárakat általában értékelnie kell, de ha el akarja kerülni az ANR-eket, akkor a főszál által igényelt erőforrásokra tartott zárakat kell megvizsgálnia.
Győződjön meg róla, hogy a zárakat a lehető legkevesebb ideig tartják, vagy még jobb,értékelje, hogy az alkalmazásnak egyáltalán szüksége van-e a zárakra. Ha a zárolást arra használja, hogy meghatározza, mikor frissítse a felhasználói felületet egy munkaszál feldolgozása alapján,használjon olyan mechanizmusokat, mint a onProgressUpdate()
és onPostExecute()
a munkaszál és a főszál közötti kommunikációhoz.
Holtpontok
Holtpont akkor keletkezik, amikor egy szál várakozó állapotba kerül, mert egy szükséges erőforrást egy másik szál tart, amely szintén az első szál által tartott erőforrásra vár. Ha az alkalmazás fő szála ilyen helyzetbe kerül, valószínűleg ANR-ek lépnek fel.
A holtpontok jól tanulmányozott jelenségek az informatikában, és léteznek holtpontmegelőző algoritmusok, amelyeket a holtpontok elkerülésére használhatunk.
Bővebb információért lásd: Deadlock andDeadlock preventiongorithms onWikipedia.
Slow broadcast receivers
Az alkalmazások broadcast vevőkészülékekkel válaszolhatnak az olyan broadcast üzenetekre, mint például a repülőgép üzemmód engedélyezése vagy letiltása vagy a kapcsolódási állapot változása. Az ANR akkor következik be, ha egy alkalmazásnak túl sokáig tart a broadcast üzenet feldolgozása.
Az ANR a következő esetekben következik be:
- A broadcast vevő nem fejezte be a
onReceive()
módszerének végrehajtását elfogadható időn belül. - Egy broadcast vevő meghívja a
goAsync()
et, és nem hívja meg afinish()
et aPendingResult
objektumon.
Az alkalmazás csak rövid műveleteket végezhet egy BroadcastReceiver
onReceive()
metódusában. Ha azonban az alkalmazásodnak egy broadcast üzenet hatására összetettebb feldolgozásra van szüksége, akkor halaszd a feladatot egy IntentService
-re.
A Traceview-hoz hasonló eszközökkel azonosíthatod, ha a broadcast-vevőd hosszú futású műveleteket hajt végre az alkalmazás főszálán. A 6. ábra például egy olyan broadcast-vevő idővonalát mutatja, amely egy üzenetet a főszálon dolgoz fel körülbelül 100 másodpercig.
6. ábra. Traceview idővonal, amely a BroadcastReceiver munkáját mutatja a főszálon
Ezt a viselkedést okozhatja a BroadcastReceiver
hosszú futású műveletek végrehajtása a onReceive()
metóduson, ahogy a következő példa mutatja:
Az ilyen helyzetekben ajánlott a hosszú futású műveletet a IntentService
be áthelyezni, mert az egy munkaszálat használ a munka végrehajtásához. A következő kód azt mutatja, hogyan használhatunk egy IntentService
-t egy hosszú futású művelet feldolgozásához:
A IntentService
használatának eredményeként a hosszú futású művelet a főszál helyett egy munkaszálon kerül végrehajtásra. A 7. ábra a Traceview idővonalán mutatja a munkaszálra halasztott munkát.
7. ábra. Traceview idővonal, amely a munkaszálon feldolgozott broadcast üzenetet mutatja
A broadcast vevője a goAsync()
használatával jelezheti a rendszernek, hogy több időre van szüksége az üzenet feldolgozásához. Azonban meg kell hívnia a finish()
-et a PendingResult
objektumon. Az alábbi példa azt mutatja, hogyan kell meghívni a finish() parancsot, hogy a rendszer újrahasznosíthassa a broadcast-vevőt és elkerülje az ANR-t:
A lassú broadcast-vevőből a kód áthelyezése egy másik szálba és a goAsync()
használata azonban nem javítja az ANR-t, ha a broadcast a háttérben van. Az ANR timeout továbbra is érvényes.
Az ANR-ekkel kapcsolatos további információkért lásd: Az alkalmazás reakcióképességének megőrzése. A szálakkal kapcsolatos további információkért lásd: Szálak teljesítménye.
Vélemény, hozzászólás?