Wenn der UI-Thread einer Android-App zu lange blockiert ist, wird ein ANR-Fehler (App antwortet nicht) ausgelöst. Wenn sich die App im Vordergrund befindet, wird dem Nutzer ein Dialogfeld angezeigt, wie in Abbildung 1 dargestellt. Im ANR-Dialogfeld kann der Nutzer das Beenden der App erzwingen.
ANR-Fehler sind ein Problem, weil der Hauptthread der App, der für die Aktualisierung der Benutzeroberfläche verantwortlich ist, keine Nutzereingabeereignisse verarbeiten oder zeichnen kann, was zu Frustration beim Nutzer führt. Weitere Informationen zum Hauptthread der App finden Sie unter Prozesse und Threads – Übersicht.
Ein ANR-Fehler wird für Ihre App ausgelöst, wenn eine der folgenden Bedingungen erfüllt ist:
- Zeitüberschreitung bei der Eingabeverteilung:Wenn deine App innerhalb von 5 Sekunden nicht auf ein Eingabeereignis (z. B. Tastendruck oder Berührung des Displays) reagiert hat.
- Dienst wird ausgeführt:Wenn ein von deiner App deklarierter Dienst
Service.onCreateundService.onStartCommand/Service.onBindnicht innerhalb weniger Sekunden ausführen kann. Service.startForegroundnicht aufgerufen:Wenn deine AppContext.startForegroundServiceverwendet, um einen neuen Dienst im Vordergrund zu starten, der Dienst aber nicht innerhalb von 5 SekundenstartForegroundaufruft.- Broadcast of Intent: Wenn ein
BroadcastReceivernicht innerhalb einer bestimmten Zeit ausgeführt wurde. Wenn die App im Vordergrund aktiv ist, beträgt dieses Zeitlimit 5 Sekunden. JobScheduler-Interaktionen: Wenn einJobServicenicht innerhalb weniger Sekunden vonJobService.onStartJoboderJobService.onStopJobzurückkehrt oder wenn ein vom Nutzer initiierter Job gestartet wird und Ihre App nicht innerhalb weniger Sekunden nach dem Aufruf vonJobService.onStartJobdie MethodeJobService.setNotificationaufruft. Bei Apps, die auf Android 13 und niedriger ausgerichtet sind, werden die ANRs im Hintergrund ausgeführt und nicht an die App gemeldet. Bei Apps, die auf Android 14 und höher ausgerichtet sind, werden die ANRs explizit an die App gemeldet.
Wenn in Ihrer App ANR-Fehler auftreten, können Sie die Anleitung in diesem Dokument verwenden, um das Problem zu diagnostizieren und zu beheben.
ANR-Fehler diagnostizieren
Bei der Diagnose von ANRs gibt es einige häufige Muster, auf die Sie achten sollten:
- Die App führt langsame Vorgänge mit E/A im Hauptthread aus.
- Die App führt eine lange Berechnung im Hauptthread aus.
- Der Hauptthread führt einen synchronen Binder-Aufruf an einen anderen Prozess aus und es dauert lange, bis dieser andere Prozess zurückgegeben wird.
- Der Hauptthread ist blockiert und befindet sich im Wartezustand für einen synchronisierten Block für einen langen Vorgang, der in einem anderen Thread ausgeführt wird.
- Der Hauptthread befindet sich in einem Deadlock mit einem anderen Thread, entweder in Ihrem Prozess oder über einen Binderaufruf. Der Hauptthread wartet nicht nur darauf, dass ein langer Vorgang abgeschlossen wird, sondern befindet sich in einer Deadlock-Situation.
Mit den folgenden Methoden können Sie die Ursache Ihrer ANRs ermitteln.
HealthStats
HealthStats liefert Messwerte zum Zustand einer Anwendung, indem die gesamte Nutzer- und Systemzeit, die CPU-Zeit, Netzwerk- und Funkstatistiken, die Zeit, in der der Bildschirm ein- und ausgeschaltet ist, sowie Weckalarme erfasst werden. So können Sie die CPU-Gesamtauslastung und den Akkuverbrauch messen.
Fehler beheben
Mit Debug können Sie Android-Apps während der Entwicklung prüfen, einschließlich Tracing und Zuordnungsanzahl, um Ruckeln und Verzögerungen in den Apps zu erkennen.
Mit Debug können Sie auch Laufzeit- und native Speicherzähler sowie Speichermesswerte abrufen, mit denen Sie den Speicherbedarf eines bestimmten Prozesses ermitteln können.
ApplicationExitInfo
ApplicationExitInfo ist unter Android 11 (API-Level 30) oder höher verfügbar und liefert Informationen zum Grund für das Beenden der App. Dazu gehören ANRs, wenig Arbeitsspeicher, App-Abstürze, übermäßige CPU-Auslastung, Unterbrechungen durch Nutzer, Systemunterbrechungen und Änderungen der Laufzeitberechtigungen.
Strenger Modus
Mit StrictMode kannst du während der Entwicklung deiner App versehentliche E/A-Vorgänge im Hauptthread finden. Du kannst StrictMode auf Anwendungs- oder Aktivitätsebene verwenden.
ANR-Dialoge im Hintergrund aktivieren
Android zeigt ANR-Dialogfelder für Apps, die zu lange für die Verarbeitung der Broadcast-Nachricht benötigen, nur dann an, wenn in den Entwickleroptionen des Geräts die Option Alle ANRs anzeigen aktiviert ist. Aus diesem Grund werden ANR-Dialogfelder im Hintergrund nicht immer angezeigt, auch wenn bei der App Leistungsprobleme auftreten.
Engpässe bei der Neuzusammensetzung
Verwenden Sie den Android Studio Profiler und den Layout Inspector, um Engpässe bei der Neuzusammensetzung zu finden. Weitere Informationen finden Sie unter Jetpack Compose-Leistung.
Trace-Datei abrufen
Android speichert Trace-Informationen, wenn ein ANR-Fehler auftritt. Bei älteren Betriebssystemversionen gibt es auf dem Gerät eine einzelne /data/anr/traces.txt-Datei. In neueren Betriebssystemversionen gibt es mehrere /data/anr/anr_*-Dateien. Du kannst über die Android Debug Bridge (ADB) als Root auf ANR-Traces von einem Gerät oder Emulator zugreifen:
adb root
adb shell ls /data/anr
adb pull /data/anr/<filename>
Du kannst einen Fehlerbericht von einem physischen Gerät erstellen, indem du entweder die Entwickleroption „Fehlerbericht abrufen“ auf dem Gerät oder den Befehl adb bugreport auf deinem Entwicklungscomputer verwendest. Weitere Informationen finden Sie unter Fehlerberichte erfassen und lesen.
Probleme beheben
Nachdem Sie das Problem identifiziert haben, können Sie die Tipps in diesem Abschnitt verwenden, um häufig auftretende Probleme zu beheben.
Langsamer Code im Hauptthread
Ermitteln Sie die Stellen im Code, an denen der Hauptthread der App länger als 5 Sekunden beschäftigt ist. Suchen Sie in Ihrer App nach verdächtigen Anwendungsfällen und versuchen Sie, den ANR-Fehler zu reproduzieren.
Ein häufiges Problem ist eine lang andauernde Aufgabe direkt in einer zusammensetzbaren Funktion:
@Composable
fun BadList(rawStrings: List<String>) {
// Math or sorting inside the composable runs on EVERY recomposition pass!
val heavilyProcessedList = rawStrings
.filter { it.isNotBlank() }
.map { it.uppercase().reversed() }
.map { it.computationallyHeavyFunction() }
.sortedBy { it.length }
LazyColumn { items(sortedList) { Text(it) } }
}
// Modern Compose-first fix
@Composable
fun GoodList(viewModel: MyViewModel = viewModel()) {
val uiState by viewModel.uiState.collectAsStateWithLifecycle()
// UI simply renders state; no heavy processing allowed here
LazyColumn { items(uiState.sortedData) { Text(it) } }
}
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, die zu ANR-Fehlern führen können. In Compose lösen Entwickler oft versehentlich Lesevorgänge auf dem Laufwerk aus (z. B. SharedPreferences oder Datenbankaufrufe), wenn sie versuchen, den Anfangszustand abzuleiten.
Führen Sie lang andauernde E/A-Vorgänge außerhalb der UI-Ebene aus. Verwenden Sie withContext(Dispatchers.IO) in einem ViewModel oder, noch besser, ein Repository auf der Datenebene.
Deadlocks
Ein Deadlock tritt auf, wenn ein Thread in einen Wartezustand wechselt, weil eine erforderliche Ressource von einem anderen Thread gehalten wird, der ebenfalls auf eine Ressource wartet, die vom ersten Thread gehalten wird. Wenn sich der Hauptthread der App in dieser Situation befindet, sind ANR-Fehler wahrscheinlich.
Deadlocks sind ein gut erforschtes Phänomen in der Informatik. Es gibt Algorithmen zur Deadlock-Vermeidung, mit denen Sie Deadlocks vermeiden können.
Weitere Informationen finden Sie unter Deadlock und Algorithmen zur Vermeidung von Deadlocks auf Wikipedia.
Wenn Sie Kotlin und Compose verwenden, können Sie primitive Sperren durch nicht blockierende Coroutine-Mutexes (Mutex.withLock) ersetzen, um das Blockieren von Threads zu verhindern. Dazu wird der Ausführungskontext ausgesetzt, anstatt den UI-Thread einzufrieren. Beispiel:
import kotlinx.coroutines.sync.Mutex
import kotlinx.coroutines.sync.withLock
// Modern non-blocking concurrency state architecture
class SecureDataRepository {
private val mutex = Mutex()
suspend fun safeUIAccess() {
// If locked, the main thread suspends seamlessly, preventing an ANR
mutex.withLock {
performSafeOperation()
}
}
}
Langsame Übertragungsempfänger
Apps können mithilfe von Übertragungsempfängern auf Broadcast-Nachrichten reagieren, z. B. auf das Aktivieren oder Deaktivieren des Flugmodus oder auf eine Änderung des Verbindungsstatus. Ein ANR-Fehler tritt auf, wenn eine App zu lange braucht, um die Broadcast-Nachricht zu verarbeiten.
Ein ANR-Fehler tritt in den folgenden Fällen auf:
- Ein Übertragungsempfänger hat die Methode
onReceivenicht innerhalb eines angemessenen Zeitraums ausgeführt. - Ein Übertragungsempfänger ruft
goAsyncauf und kannfinishnicht für dasPendingResult-Objekt aufrufen.
Ihre App sollte in der Methode onReceive eines BroadcastReceiver nur kurze Vorgänge ausführen. Wenn Ihre App jedoch aufgrund einer Nachricht an alle eine komplexere Verarbeitung erfordert, sollten Sie die Aufgabe an einen ViewModel (unter Nutzung der Leistungsfähigkeit von Kotlin-Koroutinen, -Bereichen und -Dispatchern) delegieren, wenn die Aufgabe voraussichtlich höchstens ein paar Sekunden dauert, an einen beliebigen Typ von State Holder oder an WorkManager für Aufgaben, die voraussichtlich länger als ein paar Sekunden dauern.
GameActivity
Die Bibliothek GameActivity hat in Fallstudien zu Spielen und Apps, die in C oder C++ geschrieben wurden, die Anzahl der ANRs reduziert. Wenn Sie Ihre vorhandene native Aktivität durch GameActivity ersetzen, können Sie die Blockierung des UI-Threads reduzieren und einige ANRs verhindern.
Weitere Informationen zu ANR-Fehlern finden Sie unter Keep your app responsive (Reaktionsfähigkeit der App beibehalten). Weitere Informationen zu Threads finden Sie unter Bessere Leistung durch Threading.
Zusätzliche Ressourcen
Inhalte ansehen
Empfehlungen für Sie
- Hinweis: Der Linktext wird angezeigt, wenn JavaScript deaktiviert ist.
- Übermäßige Wakeups