ANRs

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.

Abbildung 1. ANR-Dialogfeld, das dem Nutzer angezeigt wird

Abbildung 1: ANR-Dialogfeld, das dem Nutzer angezeigt wird

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() und Service.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 ruft startForeground() 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 von JobService.onStartJob() oder JobService.onStopJob() innerhalb weniger oder wenn ein vom Nutzer initiierter Job startet und Ihre App ruft nicht innerhalb weniger Sekunden JobService.setNotification() auf Sekunden, nachdem JobService.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. Traceview-Zeitachse mit einer ausgelasteten Haupt-
Thread

Abbildung 2: Traceview-Zeitachse mit einem belegten Hauptthread

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

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

Abbildung 4. Hauptthread im Monitor
Status

Abbildung 4: Hauptthread im Monitorstatus

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() am PendingResult -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.

Abbildung 5. Traceview-Zeitachse mit der Ausführung von „BroadcastReceiver“ auf der Hauptübersicht
Thread

Abbildung 5: Traceview-Zeitachse mit den Arbeiten von BroadcastReceiver auf der Hauptthread

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.

Abbildung 6. Traceview-Zeitachse, die die auf einem
Worker-Thread

Abbildung 6: Traceview-Zeitachse, die die auf einem Worker-Thread

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: