Wenn der UI-Thread einer Android-App zu lange blockiert ist, Keine Reaktion“ (ANR) ausgelöst. Wenn die App im Vordergrund ausgeführt wird, zeigt dem Nutzer ein Dialogfeld an, wie in Abbildung 1 dargestellt. Im ANR-Dialogfeld wird Nutzenden die Möglichkeit, das Beenden der App zu erzwingen.
ANR-Fehler stellen ein Problem dar, weil der Hauptthread der App, der für Benutzereingabeereignisse nicht verarbeiten oder Zeichnungen erstellen können, was zu Frustration Nutzenden. Weitere Informationen zum Hauptthread der App finden Sie unter Prozesse und Threads
Ein ANR-Fehler wird für Ihre App ausgelöst, wenn eine der folgenden Bedingungen eintritt:
- Zeitüberschreitung bei der Eingabeversand:Ihre App hat auf eine Eingabe nicht reagiert. (z. B. Tastendruck oder Bildschirmberührung) innerhalb von 5 Sekunden.
- Dienst wird ausgeführt:Wenn ein von Ihrer App deklarierter Dienst nicht abgeschlossen werden kann
Ausführung von
Service.onCreate()
undService.onStartCommand()
/Service.onBind()
innerhalb weniger Sekunden. - Service.startForeground() nicht aufgerufen:Wenn Ihre App
Context.startForegroundService()
, um einen neuen Dienst im Vordergrund zu starten, aber der Dienst ruftstartForeground()
dann nicht innerhalb von 5 Sekunden auf. - Übertragung der Absicht:Wenn eine
BroadcastReceiver
Ausführung innerhalb eines festgelegten Zeitraums nicht abgeschlossen hat. Wenn die App über Aktivität im Vordergrund liegt, beträgt dieses Zeitlimit 5 Sekunden. - Interaktionen mit Job Scheduler: Wenn ein
JobService
gibt nicht zurück vonJobService.onStartJob()
oderJobService.onStopJob()
innerhalb weniger oder wenn ein vom Nutzer initiierter Job startet und Ihre App ruft nicht innerhalb weniger SekundenJobService.setNotification()
auf Sekunden, nachdemJobService.onStartJob()
aufgerufen wurde. Für App-Targeting Bei Android 13 und niedriger sind die ANR-Fehler im Hintergrund und werden nicht an die App gemeldet. Bei Apps, die auf Android 14 und höher ausgerichtet sind, sind die ANR-Fehler explizit und werden an die App gemeldet.
Wenn in deiner App ANR-Fehler auftreten, kannst du anhand der Anleitung in diesem Artikel Folgendes tun: Problem zu diagnostizieren und zu beheben.
Problem erkennen
Wenn Sie Ihre App bereits veröffentlicht haben, können Sie In Android Vitals findest du Informationen zu ANR-Fehlern für deine App. Sie können andere zur Erkennung von ANR-Fehlern vor Ort verwendet werden. Drittanbietertools können ältere Versionen von Android (Android 10 und niedriger) im Gegensatz zu Android Vitals.
Android Vitals
Mit Android Vitals kannst du die ANR-Rate deiner App beobachten und verbessern. In Android Vitals werden mehrere ANR-Raten erfasst:
- ANR-Rate:Prozentsatz der aktiven Nutzer pro Tag, die Es ist ein ANR-Fehler aufgetreten.
- Vom Nutzer wahrgenommene ANR-Rate:Prozentsatz der aktiven Nutzer pro Tag
bei denen mindestens ein vom Nutzer wahrgenommener ANR-Fehler aufgetreten ist. Aktuell sind nur ANR-Fehler von
Input dispatching timed out
gelten als vom Nutzer wahrgenommen. - Mehrfach-ANR-Rate:Prozentsatz der aktiven Nutzer pro Tag, die ist mindestens zwei ANR-Fehler aufgetreten.
Ein aktiver Nutzer pro Tag ist ein einzelner Nutzer, der Ihre App verwendet. an einem einzigen Tag und auf einem einzigen Gerät durchführen, möglicherweise über mehrere Sitzungen hinweg. Verwendet ein Nutzer Ihre App an einem Tag auf mehreren Geräten, wie jedes Gerät zur Anzahl der aktiven Nutzer am jeweiligen Tag beiträgt. Wenn mehrere Nutzer dasselbe Gerät an einem Tag verwenden, zählt das als ein aktiver Nutzer.
Die vom Nutzer wahrgenommene ANR-Rate ist ein Vitalparameter, was bedeutet, dass sie Sichtbarkeit deiner App bei Google Play. Es ist wichtig, da die ANR-Fehler werden immer dann gezählt, wenn der Nutzer mit der App interagiert, Störungen.
Google Play hat für diesen Messwert zwei Grenzwerte zu unerwünschtem Verhalten definiert:
- Grenzwert zu unerwünschtem Verhalten insgesamt:Mindestens 0,47% der aktiven Nutzer pro Tag auf allen Gerätemodellen einen vom Nutzer wahrgenommenen ANR-Fehler auftreten.
- Grenzwert zu unerwünschtem Verhalten pro Gerät:Mindestens 8% der Nutzer pro Tag bei einem einzelnen Gerätemodell einen vom Nutzer wahrgenommenen ANR-Fehler verursachen.
Überschreitet Ihre App den Grenzwert zu unerwünschtem Verhalten insgesamt, ist es höchstwahrscheinlich auf allen Geräten weniger gut sichtbar sind. Wenn deine App den Wert für „Programmfehler“ pro Gerät überschreitet auf einigen Geräten angezeigt wird, ist es auf Geräten mit und in deinem Store-Eintrag wird möglicherweise eine Warnung angezeigt.
Android Vitals kann dich über die Play Console wenn Ihre App übermäßige ANR-Fehler aufweist.
Informationen dazu, wie Google Play Android Vitals-Daten erhebt, findest du in den Play Console Dokumentation.
ANR-Fehler diagnostizieren
Bei der Diagnose von ANR-Fehlern sollten Sie auf einige gängige Muster achten:
- Die App führt langsame Vorgänge mit E/A im Hauptthread aus.
- Die App führt eine lange Berechnung im Hauptthread durch.
- Der Hauptthread führt einen synchronen Binder-Aufruf an einen anderen Prozess aus. dass ein anderer Prozess lange dauert.
- Der Hauptthread ist blockiert, weil er lange auf einen synchronisierten Block wartet Vorgang in einem anderen Thread.
- Der Hauptthread befindet sich in einem Deadlock mit einem anderen Thread, entweder in Ihrem oder über einen Binder-Aufruf. Der Hauptthread wartet nicht nur lange der Vorgang abgeschlossen ist, jedoch in einem Deadlock-Situation ist. Weitere Informationen siehe Deadlock bei Wikipedia.
Die folgenden Methoden können Ihnen helfen, die Ursache von ANR-Fehlern zu ermitteln.
Gesundheitsstatistiken
HealthStats
enthält Messwerte zu
die Integrität einer Anwendung prüfen, indem
die Nutzer- und Systemzeit, die CPU-Zeit
Netzwerk, Radiostatistiken, Bildschirmzeit zum Ein-/Ausschalten und Weckrufe. Dies kann
bei der Messung der CPU-Auslastung
und der Akkuentladung insgesamt.
Fehler beheben
Debug
hilft bei der Prüfung von Android-Apps
während der Entwicklung, einschließlich Tracing und Zuweisungszahlen zur Identifizierung von Verzögerungen
und Verzögerungen bei den Apps. Sie können auch Debug
verwenden, um Laufzeit und nativen Arbeitsspeicher abzurufen
Zähler und Arbeitsspeichermesswerte, die bei der Identifizierung des Arbeitsspeicher-Fußabdrucks helfen können.
eines bestimmten Prozesses.
Informationen zum Anwendungs-Exit
ApplicationExitInfo
ist verfügbar
Android 11 (API-Level 30) oder höher installiert. Außerdem finden Sie dort
den Grund für das Beenden der App. Dazu gehören ANRs, wenig Arbeitsspeicher, App-Abstürze,
übermäßige CPU-Auslastung, Nutzerunterbrechungen, Systemunterbrechungen oder Laufzeiten
Änderungen der Berechtigungen.
Strenger Modus
Mit StrictMode
können Sie
versehentlichen E/A-Vorgängen im Hauptthread vor, während Sie Ihre App entwickeln.
Sie können StrictMode
verwenden.
auf Anwendungs- oder Aktivitätsebene.
ANR-Dialogfelder im Hintergrund aktivieren
Android zeigt ANR-Dialogfelder für Apps an, deren Verarbeitung der Übertragung zu lange dauert Alle ANR-Fehler anzeigen auf der Seite Entwickler Optionen. Aus diesem Grund werden ANR-Fehler im Hintergrund für Nutzer aber dennoch können Leistungsprobleme bei der App auftreten.
TraceView
Mit Traceview können Sie einen Trace Ihrer laufenden App abrufen, während Sie die Anwendungsfälle ermittelt und die Stellen identifiziert, an denen der Hauptthread beschäftigt ist. Weitere Informationen zur Verwendung von Traceview finden Sie unter Profilerstellung mit Traceview und dmtracedump.
Traces-Datei abrufen
Android speichert Trace-Informationen, wenn ein ANR-Fehler auftritt. Älteres Betriebssystem
Veröffentlichungen befindet sich eine einzelne /data/anr/traces.txt
-Datei auf dem Gerät.
Auf neueren Betriebssystemversionen gibt es mehrere /data/anr/anr_*
-Dateien.
Sie können von einem Gerät oder Emulator auf ANR-Traces zugreifen, indem Sie
Android Debug Bridge (ADB) als Root:
adb root
adb shell ls /data/anr
adb pull /data/anr/<filename>
Sie können einen Fehlerbericht von einem physischen Gerät erfassen, indem Sie entweder die Schaltfläche die Option zum Melden des Entwicklers auf dem Gerät oder den Befehl „adb Bugreport“ Entwicklungsmaschine. Weitere Informationen finden Sie unter Fehler erfassen und lesen. berichten.
Probleme beheben
Sobald Sie das Problem identifiziert haben, können Sie die Tipps in diesem Abschnitt anwenden, um häufig auftretende Probleme zu beheben.
Langsamer Code im Hauptthread
Stellen Sie fest, an welchen Stellen in Ihrem Code der Hauptthread der App beschäftigt ist. als 5 Sekunden. Suchen Sie in Ihrer App nach verdächtigen Anwendungsfällen und versuchen Sie, den ANR-Fehler reproduzieren.
Abbildung 2 zeigt beispielsweise eine Traceview-Zeitachse, in der der Hauptthread ausgelastet ist. als fünf Sekunden lang.
Abbildung 2 zeigt, dass der Großteil des problematischen Codes in der
onClick(View)
wie im folgenden Codebeispiel gezeigt:
Kotlin
override fun onClick(v: View) { // This task runs on the main thread. BubbleSort.sort(data) }
Java
@Override public void onClick(View view) { // This task runs on the main thread. BubbleSort.sort(data); }
In diesem Fall sollten Sie die im Hauptthread ausgeführte Arbeit in einen Worker verschieben Diskussions-Thread. Das Android-Framework enthält Klassen, die beim Verschieben der Aufgabe helfen können. an einen Worker-Thread senden. Siehe Worker Threads Informationen.
E/A im Hauptthread
Das Ausführen von E/A-Vorgängen im Hauptthread ist eine häufige Ursache für langsame Vorgänge im Hauptthread, was zu ANR-Fehlern führen kann. Es wird empfohlen, alle Anzeigenaufträge Vorgänge in einen Worker-Thread übertragen, wie im vorherigen Abschnitt gezeigt.
Einige Beispiele für E/A-Vorgänge sind Netzwerk- und Speichervorgänge. Weitere Informationen finden Sie unter Durchführung von Vorgänge und Speichern Daten.
Konflikt durch Sperre
In einigen Szenarien werden die Vorgänge, die den ANR-Fehler verursachen, nicht direkt auf dem Hauptthread der App. Wenn ein Worker-Thread eine Sperre für eine Ressource enthält, die die Haupt- die Arbeit eines Threads abschließen muss, kann ein ANR-Fehler auftreten.
Abbildung 3 zeigt beispielsweise eine Traceview-Zeitachse, in der die meiste Arbeit die in einem Worker-Thread ausgeführt wurden.
Abbildung 3: Traceview-Zeitachse, die zeigt, wie die Arbeit auf einem Worker ausgeführt wird Thread
Wenn bei Ihren Nutzern jedoch weiterhin ANR-Fehler auftreten, sollten Sie sich den Status der
im Hauptthread im Android Device Monitor. Normalerweise befindet sich der Hauptthread im
RUNNABLE
wenn er zur Aktualisierung der Benutzeroberfläche bereit ist
und im Allgemeinen responsiv ist.
Wenn der Hauptthread jedoch die Ausführung nicht fortsetzen kann,
BLOCKED
-Status
und nicht auf Ereignisse reagieren. Der Status wird im Android Device Monitor
Monitor (Überwachen) oder Warten (Warten), wie in Abbildung 5 gezeigt
Das folgende Trace zeigt den Hauptthread einer App, der durch Warten auf eine Ressource:
...
AsyncTask #2" prio=5 tid=18 Runnable
| group="main" sCount=0 dsCount=0 obj=0x12c333a0 self=0x94c87100
| sysTid=25287 nice=10 cgrp=default sched=0/0 handle=0x94b80920
| state=R schedstat=( 0 0 0 ) utm=757 stm=0 core=3 HZ=100
| stack=0x94a7e000-0x94a80000 stackSize=1038KB
| held mutexes= "mutator lock"(shared held)
at com.android.developer.anrsample.BubbleSort.sort(BubbleSort.java:8)
at com.android.developer.anrsample.MainActivity$LockTask.doInBackground(MainActivity.java:147)
- locked <0x083105ee> (a java.lang.Boolean)
at com.android.developer.anrsample.MainActivity$LockTask.doInBackground(MainActivity.java:135)
at android.os.AsyncTask$2.call(AsyncTask.java:305)
at java.util.concurrent.FutureTask.run(FutureTask.java:237)
at android.os.AsyncTask$SerialExecutor$1.run(AsyncTask.java:243)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1133)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:607)
at java.lang.Thread.run(Thread.java:761)
...
Die Überprüfung des Trace kann Ihnen dabei helfen, den Code zu finden, der den Hauptthread blockiert. Der folgende Code ist für das Halten des Schlosses verantwortlich, das die Haupt- Thread im vorherigen Trace:
Kotlin
override fun onClick(v: View) { // The worker thread holds a lock on lockedResource LockTask().execute(data) synchronized(lockedResource) { // The main thread requires lockedResource here // but it has to wait until LockTask finishes using it. } } class LockTask : AsyncTask<Array<Int>, Int, Long>() { override fun doInBackground(vararg params: Array<Int>): Long? = synchronized(lockedResource) { // This is a long-running operation, which makes // the lock last for a long time BubbleSort.sort(params[0]) } }
Java
@Override public void onClick(View v) { // The worker thread holds a lock on lockedResource new LockTask().execute(data); synchronized (lockedResource) { // The main thread requires lockedResource here // but it has to wait until LockTask finishes using it. } } public class LockTask extends AsyncTask<Integer[], Integer, Long> { @Override protected Long doInBackground(Integer[]... params) { synchronized (lockedResource) { // This is a long-running operation, which makes // the lock last for a long time BubbleSort.sort(params[0]); } } }
Ein weiteres Beispiel ist der Hauptthread einer App, der auf ein Ergebnis einer
Worker-Thread, wie im folgenden Code dargestellt. Beachten Sie, dass die Verwendung von wait()
und
notify()
ist kein empfohlenes Muster in Kotlin, da es eigene Mechanismen hat.
für den Umgang mit Nebenläufigkeit. Bei der Verwendung von Kotlin sollten Sie Kotlin-spezifische
wenn möglich.
Kotlin
fun onClick(v: View) { val lock = java.lang.Object() val waitTask = WaitTask(lock) synchronized(lock) { try { waitTask.execute(data) // Wait for this worker thread’s notification lock.wait() } catch (e: InterruptedException) { } } } internal class WaitTask(private val lock: java.lang.Object) : AsyncTask<Array<Int>, Int, Long>() { override fun doInBackground(vararg params: Array<Int>): Long? { synchronized(lock) { BubbleSort.sort(params[0]) // Finished, notify the main thread lock.notify() } } }
Java
public void onClick(View v) { WaitTask waitTask = new WaitTask(); synchronized (waitTask) { try { waitTask.execute(data); // Wait for this worker thread’s notification waitTask.wait(); } catch (InterruptedException e) {} } } class WaitTask extends AsyncTask<Integer[], Integer, Long> { @Override protected Long doInBackground(Integer[]... params) { synchronized (this) { BubbleSort.sort(params[0]); // Finished, notify the main thread notify(); } } }
Es gibt andere Situationen, in denen der Hauptthread blockiert werden kann:
Threads, die Lock
verwenden,
Semaphore
,
sowie einen Ressourcenpool (z. B. ein Pool von Datenbankverbindungen)
oder andere Mechanismen zum gegenseitigen Ausschluss (Humex).
Sie sollten die Sperren Ihrer App für Ressourcen im Allgemeinen prüfen, aber Wenn Sie ANR-Fehler vermeiden möchten, sollten Sie sich die für Ressourcen für den Hauptthread erforderlich ist.
Achten Sie darauf, dass die Sperren so kurz oder noch besser gehalten werden,
um zu prüfen, ob für die App überhaupt ein Hold erforderlich ist. Wenn Sie den
Sperren, um zu bestimmen, wann die Benutzeroberfläche basierend auf der Verarbeitung eines Worker-Threads aktualisiert werden soll,
nutzen Mechanismen wie
onProgressUpdate()
und
onPostExecute()
für die Kommunikation zwischen
Worker- und Hauptthreads.
Deadlocks
Ein Deadlock tritt auf, wenn ein Thread in den Wartestatus wechselt, weil ein erforderlicher Ressource wird von einem anderen Thread gehalten, der ebenfalls auf eine Ressource wartet, die von im ersten Thread. Wenn sich der Hauptthread der App in dieser Situation befindet, sind ANR-Fehler wahrscheinlich möglich ist.
Deadlocks sind ein gut erforschtes Phänomen in der Informatik. Es gibt mit denen Sie Deadlocks vermeiden können.
Weitere Informationen finden Sie unter Deadlock und Schutz vor Deadlocks Algorithmen aktiviert Wikipedia:
Langsame Übertragungsempfänger
Apps können auf Nachrichten an alle antworten, z. B. um Flugzeuge zu aktivieren oder zu deaktivieren oder eine Änderung des Verbindungsstatus mithilfe von Übertragungsempfängern aktiviert hat. Ein ANR-Fehler tritt auf, wenn eine App zu lange benötigt, um die Broadcast-Nachricht zu verarbeiten.
In folgenden Fällen tritt ein ANR-Fehler auf:
- Ein Übertragungsempfänger hat seine Ausführung noch nicht beendet.
onReceive()
innerhalb eines angemessenen Zeitraums. - Ein Übertragungsempfänger ruft an
goAsync()
und ruft nicht auf,finish()
amPendingResult
-Objekt enthält.
Ihre App sollte nur kurze Vorgänge im
onReceive()
eines
BroadcastReceiver
Wenn Ihre App jedoch komplexere
als Folge einer Broadcast-Nachricht verarbeitet wird, sollten Sie die Aufgabe
IntentService
Mit Tools wie Traceview können Sie ermitteln, Vorgänge mit langer Ausführungszeit im Hauptthread der App. Abbildung 6 zeigt beispielsweise die Zeitachse eines Übertragungsempfängers, der eine Nachricht im Hauptthread verarbeitet etwa 100 Sekunden lang.
Dies kann durch lang andauernde Vorgänge auf der
onReceive()
der Methode
BroadcastReceiver
,
Dies wird im folgenden Beispiel gezeigt:
Kotlin
override fun onReceive(context: Context, intent: Intent) { // This is a long-running operation BubbleSort.sort(data) }
Java
@Override public void onReceive(Context context, Intent intent) { // This is a long-running operation BubbleSort.sort(data); }
In Situationen wie diesen empfiehlt es sich, den Vorgang mit langer Ausführungszeit
ein IntentService
, weil dabei
eines Worker-Threads,
um seine Arbeit auszuführen. Der folgende Code zeigt, wie ein
IntentService
, um ein
lang andauernden Vorgang:
Kotlin
override fun onReceive(context: Context, intent: Intent) { Intent(context, MyIntentService::class.java).also { intentService -> // The task now runs on a worker thread. context.startService(intentService) } } class MyIntentService : IntentService("MyIntentService") { override fun onHandleIntent(intent: Intent?) { BubbleSort.sort(data) } }
Java
@Override public void onReceive(Context context, Intent intent) { // The task now runs on a worker thread. Intent intentService = new Intent(context, MyIntentService.class); context.startService(intentService); } public class MyIntentService extends IntentService { @Override protected void onHandleIntent(@Nullable Intent intent) { BubbleSort.sort(data); } }
Wenn Sie die
IntentService
, das seit Langem bestehende
wird in einem Worker-Thread statt im Hauptthread ausgeführt. Abbildung 7
zeigt die auf den Worker-Thread aufgeschobene Arbeit in der Traceview-Zeitachse.
Der Übertragungsempfänger kann Folgendes verwenden:
goAsync()
um dem System zu signalisieren, dass es mehr Zeit zur Verarbeitung der Nachricht benötigt. Sie können jedoch
solltest du anrufen
finish()
am
PendingResult
-Objekt enthält. Das folgende Beispiel zeigt, wie "Finish()" aufgerufen wird, damit das System
Broadcast-Empfänger in einer anderen Phase zurückgeben, um einen ANR-Fehler zu vermeiden:
Kotlin
val pendingResult = goAsync() object : AsyncTask<Array<Int>, Int, Long>() { override fun doInBackground(vararg params: Array<Int>): Long? { // This is a long-running operation BubbleSort.sort(params[0]) pendingResult.finish() return 0L } }.execute(data)
Java
final PendingResult pendingResult = goAsync(); new AsyncTask<Integer[], Integer, Long>() { @Override protected Long doInBackground(Integer[]... params) { // This is a long-running operation BubbleSort.sort(params[0]); pendingResult.finish(); } }.execute(data);
Das Verschieben des Codes von einem langsamen Übertragungsempfänger in einen anderen Thread und
mit goAsync()
wird der ANR-Fehler nicht behoben, wenn die Übertragung im Hintergrund läuft.
Das ANR-Zeitlimit gilt weiterhin.
Spielaktivität
Die Bibliothek GameActivity
hat ANR-Fehler in
Fallstudien zu geschriebenen Spielen und Apps
in C oder C++. Wenn Sie Ihre vorhandene native Aktivität durch GameActivity
ersetzen,
können Sie das Blockieren von UI-Threads reduzieren und einige ANR-Fehler verhindern.
Weitere Informationen zu ANR-Fehlern findest du unter So bleibt deine App reaktionsschnell. Weitere Informationen Informationen zu Threads finden Sie Threading-Leistung:
Empfehlungen für dich
- Hinweis: Der Linktext wird angezeigt, wenn JavaScript deaktiviert ist.
- Übermäßige Wakeups