Abbildung 1 : Ein ANR-Dialogfeld, das dem Nutzer angezeigt wird.
In diesem Dokument wird beschrieben, wie das Android-System feststellt, ob eine App nicht reagiert, und wie Sie dafür sorgen können, dass Ihre App reaktionsschnell bleibt.
Auch wenn Ihr Code gut geschrieben ist, kann es vorkommen, dass Ihre App langsam reagiert, hängen bleibt, für längere Zeit einfriert oder zu lange braucht, um Eingaben zu verarbeiten. Wenn Ihre App im Vordergrund ist und nicht reagiert, wird dem Nutzer ein Dialogfeld „App antwortet nicht“ (Application Not Responding, ANR) angezeigt, wie in Abbildung 1 dargestellt. Im ANR-Dialogfeld kann der Nutzer die App beenden. Wenn die App nicht im Vordergrund ist, wird sie im Hintergrund beendet. Es ist wichtig, die Reaktionsfähigkeit in Ihre App zu integrieren, um ANR-Dialogfelder zu minimieren.
ANR-Auslöser
Normalerweise zeigt das System einen ANR-Fehler an, wenn eine App nicht auf Nutzereingaben im Hauptthread (auch UI-Thread genannt) reagieren kann. Dadurch kann das System keine eingehenden Nutzereingabeereignisse verarbeiten.
Ein ANR-Fehler kann beispielsweise auftreten, wenn eine App eine blockierende E/A-Operation wie den Netzwerkzugriff im UI-Thread ausführt. Ein weiteres Beispiel ist, wenn eine App zu viel Zeit damit verbringt, eine komplexe In-Memory-Struktur zu erstellen oder den nächsten Zug in einem Spiel im UI-Thread zu berechnen.
In Android wird die Reaktionsfähigkeit von Apps von den ActivityManager und
WindowManager Systemdiensten überwacht. Android zeigt das ANR-Dialogfeld für eine App an, wenn eine der folgenden Bedingungen erfüllt ist:
- Innerhalb von 5 Sekunden erfolgt keine Reaktion auf ein Eingabeereignis wie einen Tastendruck oder eine Bildschirmberührung.
- Ein
BroadcastReceiverwird bei Vordergrund-Intents nicht innerhalb von 10 bis 20 Sekunden ausgeführt. Weitere Informationen finden Sie unter Übertragungsempfänger-Timeout.
ANR-Fehler vermeiden
Im Folgenden finden Sie allgemeine Tipps, wie Sie ANR-Fehler vermeiden können. Weitere Informationen zum Diagnostizieren und Debuggen verschiedener Arten von ANR-Fehlern finden Sie auf den anderen Seiten in diesem Abschnitt.
Halten Sie den Hauptthread immer frei und verwenden Sie Threads strategisch.
Führen Sie keine blockierenden oder lang andauernden Vorgänge im Hauptthread der App aus. Verwenden Sie stattdessen Kotlin-Coroutinen, um die Arbeit an Hintergrund-Dispatcher auszulagern, z. B.
Dispatchers.IOoderDispatchers.Default. Verwenden Sie Mechanismen wieviewModelScope, um diese Hintergrundaufgaben sicher zu starten, oderLaunchedEffect, um sie als Reaktion auf Änderungen des Compose-Status auszulösen.Versuchen Sie, die Sperrenkonkurrenz zwischen dem Hauptthread und anderen Threads zu minimieren.
Minimieren Sie alle nicht UI-bezogenen Arbeiten im Hauptthread, z. B. beim Verarbeiten von Broadcasts oder Ausführen von Diensten. Jede Methode oder Funktion, die im UI-Thread ausgeführt wird, muss so wenig Arbeit wie möglich erledigen. Insbesondere Aktivitäten müssen so wenig wie möglich tun, um in wichtigen Lebenszyklusmethoden wie
onCreateundonResumeeingerichtet zu werden. Führen Sie niemals E/A- oder rechenintensive, blockierende Berechnungen direkt in einer zusammensetzbaren Funktion aus. Dadurch wird der UI-Thread während der Komposition und Neukomposition blockiert. Weitere Informationen zu verfügbaren Lösungen zum Planen von Aufgaben in einem Hintergrundthread und zur Kommunikation mit der UI finden Sie unter Übersicht über Hintergrundaufgaben.Seien Sie vorsichtig, wenn Sie Threadpools zwischen Komponenten freigeben. Verwenden Sie nicht dieselben Threads für potenziell lange blockierende Vorgänge und zeitkritische Aufgaben wie den Empfang von Broadcasts.
Sorgen Sie für einen schnellen App-Start. Minimieren Sie langsame oder blockierende Vorgänge im Startcode der App, z. B. Methoden, die während der Einrichtung der Abhängigkeitsinjektion (z. B. mit Hilt) ausgeführt werden, oder Komponenten, die mit der Jetpack App Startup-Bibliothekinitialisiert werden. Sie können den App-Start mit Baseline-Profilen, Startprofilen und R8 weiter optimieren.
Wenn Sie
BroadcastReceiververwenden, sollten Sie Broadcast-Receiver in einem Nicht-Hauptthread mitContext.registerReceiverausführen. Weitere Informationen finden Sie unter ANR-Fehler in BroadcastReceiver.- Wenn Sie
goAsyncverwenden, mussPendingResult.finishschnell vor dem ANR-Timeout aufgerufen werden.
- Wenn Sie
ANR-Fehler in BroadcastReceiver
BroadcastReceiver Die Ausführungszeit ist begrenzt, da Broadcast-Receiver
kleine, diskrete Aufgaben im Hintergrund ausführen sollen, z. B.
eine Einstellung speichern oder einen Notification registrieren. Wie bei anderen Methoden, die im UI-Thread aufgerufen werden, müssen Apps potenziell lang andauernde Vorgänge oder Berechnungen in einem Übertragungsempfänger vermeiden. Führen Sie lang andauernde Aufgaben nicht über den UI-Thread aus, sondern im Hintergrund, damit sie später ausgeführt werden können. Weitere Informationen zu
möglichen Lösungen finden Sie unter Übersicht über Hintergrundaufgaben.
Ein weiteres häufiges Problem mit BroadcastReceiver-Objekten tritt auf, wenn sie zu häufig ausgeführt werden. Eine häufige Ausführung im Hintergrund kann die Menge an Arbeitsspeicher reduzieren, die anderen Apps zur Verfügung steht. Weitere Informationen zum effizienten Aktivieren und Deaktivieren von
BroadcastReceiver Objekten finden Sie unter Übersicht über Broadcasts.
Reaktionsfähigkeit verbessern
Im Allgemeinen liegt die Schwelle, ab der Nutzer eine App als langsam empfinden, bei 100 bis 200 ms. Hier sind weitere Tipps, wie Sie dafür sorgen können, dass Ihre App für Nutzer reaktionsschnell wirkt:
Wenn Ihre App im Hintergrund auf Nutzereingaben reagiert, zeigen Sie den Fortschritt an, z. B. mit einem
CircularProgressIndicatoroderLinearProgressIndicatorin der UI.Bei Spielen sollten Sie Berechnungen für Züge in einer Hintergrund-Koroutine oder einem Arbeitsthread ausführen.
Wenn Ihre App eine zeitaufwendige Ersteinrichtungsphase hat, sollten Sie einen Splash-Screen anzeigen oder Ihre erste Komposition so schnell wie möglich rendern. Geben Sie an, dass der Ladevorgang läuft, und füllen Sie den UI-Status asynchron aus. In beiden Fällen empfehlen wir, irgendwie anzugeben, dass Fortschritte erzielt werden, damit der Nutzer nicht den Eindruck hat, dass die App eingefroren ist.
Verwenden Sie Leistungstools wie Perfetto und CPU Profiler, um Engpässe in der Reaktionsfähigkeit Ihrer App zu ermitteln.