Wenn der UI-Thread einer Android-App zu lange blockiert wird, wird ein ANR-Fehler (Application Not Responding) ausgelöst. Wenn sich die App im Vordergrund befindet, wird dem Nutzer ein Dialogfeld angezeigt, wie in Abbildung 1 dargestellt. Im ANR-Dialogfeld hat der Nutzer die Möglichkeit, die App zu schließen.
ANR-Fehler sind ein Problem, weil der Hauptthread der App, der für die Aktualisierung der Benutzeroberfläche zuständig 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 wird für Ihre App ausgelöst, wenn eine der folgenden Bedingungen eintritt:
- Zeitüberschreitung beim Senden der Eingabe:Wenn Ihre App innerhalb von 5 Sekunden nicht auf ein Eingabeereignis (z. B. einen Tastendruck oder eine Bildschirmberührung) reagiert hat.
- Ausführung des Dienstes:Wenn ein von Ihrer App deklarierter Dienst die Ausführung von
Service.onCreateundService.onStartCommand/Service.onBindnicht innerhalb weniger Sekunden abschließen kann. Service.startForegroundnicht aufgerufen:Wenn Ihre AppContext.startForegroundServiceverwendet, um einen neuen Dienst im Vordergrund zu starten, der Dienst aberstartForegroundnicht innerhalb von 5 Sekunden aufruft.- Broadcast of intent (Absichtssendung): Wenn die Ausführung eines
BroadcastReceivernicht innerhalb eines bestimmten Zeitraums abgeschlossen ist. Wenn die App im Vordergrund aktiv ist, beträgt das Zeitlimit 5 Sekunden. JobScheduler-Interaktionen:Wenn eineJobServicenicht innerhalb weniger Sekunden vonJobService.onStartJoboderJobService.onStopJobzurückgegeben wird oder wenn ein vom Nutzer initiierter Job gestartet wird und Ihre App nicht innerhalb weniger Sekunden nach dem Aufruf vonJobService.onStartJobJobService.setNotificationaufruft. Bei Apps, die auf Android 13 und niedriger ausgerichtet sind, werden ANRs nicht gemeldet. Bei Apps, die auf Android 14 und höher ausgerichtet sind, werden ANRs explizit gemeldet.
Wenn in Ihrer App ANRs auftreten, können Sie das Problem mithilfe der Informationen in diesem Dokument diagnostizieren und 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-Vorgängen 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 dieser Prozess benötigt lange, um zurückzukehren.
- Der Hauptthread ist blockiert und wartet auf einen synchronisierten Block für einen langwierigen 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 Binder-Aufruf. Der Hauptthread wartet nicht nur darauf, dass ein langer Vorgang abgeschlossen wird, sondern befindet sich in einer Deadlock-Situation.
Die folgenden Techniken können Ihnen helfen, die Ursache Ihrer ANRs zu ermitteln.
HealthStats
HealthStats bietet Messwerte zum Zustand einer Anwendung, indem die gesamte Nutzer- und Systemzeit, die CPU-Zeit, Netzwerk- und Funkstatistiken, die Zeit, in der das Display 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-Anwendungen während der Entwicklung untersuchen, einschließlich Tracing und Zuweisungsanzahl, um Ruckeln und Verzögerungen in den Apps zu erkennen.
Mit Debug können Sie auch Laufzeit- und native Arbeitsspeicherzähler sowie Arbeitsspeichermesswerte abrufen, mit denen Sie den Speicherbedarf eines bestimmten Prozesses ermitteln können.
ApplicationExitInfo
ApplicationExitInfo ist für Android 11 (API-Level 30) oder höher verfügbar und enthält Informationen zum Grund für das Beenden der Anwendung. Dazu gehören ANRs, wenig Speicherplatz, App-Abstürze, übermäßige CPU-Nutzung, Nutzerunterbrechungen, Systemunterbrechungen und Änderungen der Laufzeitberechtigungen.
Strenger Modus
Mit StrictMode können Sie während der Entwicklung Ihrer App versehentliche E/A-Vorgänge im Hauptthread finden. Sie können StrictMode auf Anwendungs- oder Aktivitätsebene verwenden.
ANR-Dialoge im Hintergrund aktivieren
Unter Android werden ANR-Dialogfelder für Apps, die zu lange für die Verarbeitung der Broadcast-Nachricht benötigen, nur angezeigt, wenn in den Entwickleroptionen des Geräts die Option Alle ANRs anzeigen aktiviert ist. Aus diesem Grund werden ANR-Dialogfelder im Hintergrund nicht immer für den Nutzer angezeigt, auch wenn bei der App Leistungsprobleme auftreten.
Engpässe bei der Neuzusammenstellung
Verwende den Android Studio Profiler und den Layout Inspector, um Engpässe bei der Neukomposition zu ermitteln. Weitere Informationen finden Sie unter Jetpack Compose-Leistung.
Trace-Datei abrufen
Android speichert Trace-Informationen, wenn ein ANR 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. Sie können über 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>
Sie können einen Fehlerbericht von einem physischen Gerät erstellen, indem Sie entweder die Entwickleroption „Fehlerbericht abrufen“ auf dem Gerät oder den adb bugreport-Befehl auf Ihrem Entwicklercomputer verwenden. 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
Suchen Sie in Ihrem Code nach Stellen, an denen der Haupt-Thread der App länger als 5 Sekunden beschäftigt ist. Suchen Sie in Ihrer App nach den verdächtigen Anwendungsfällen und versuchen Sie, den ANR zu reproduzieren.
Ein häufiges Problem ist eine lang andauernde Aufgabe direkt in einem Composable:
@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
Die Ausführung 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 beim Versuch, den Anfangszustand abzuleiten, oft versehentlich Festplattenlesevorgänge (z. B. SharedPreferences oder Datenbankaufrufe) aus.
Führen Sie E/A-Vorgänge mit langer Ausführungszeit außerhalb der UI-Ebene aus. Verwenden Sie withContext(Dispatchers.IO) in einem ViewModel oder noch besser ein Repository in der Datenschicht.
Deadlocks
Ein Deadlock tritt auf, wenn ein Thread in den Wartestatus 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, treten wahrscheinlich ANR-Fehler auf.
Deadlocks sind ein in der Informatik gut untersuchtes Phänomen. Es gibt Algorithmen zur Vermeidung von Deadlocks, die Sie verwenden können, um Deadlocks zu vermeiden.
Weitere Informationen finden Sie auf Wikipedia unter Deadlock und Deadlock prevention algorithms.
Wenn Sie Kotlin und Compose verwenden, können Sie primitive Locks durch nicht blockierende Coroutine-Mutexes (Mutex.withLock) ersetzen, um zu verhindern, dass Threads blockiert werden. Stattdessen wird der Ausführungskontext angehalten, 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 Broadcast-Empfä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 für die Verarbeitung der Nachricht an alle benötigt.
Ein ANR-Fehler tritt in den folgenden Fällen auf:
- Ein Übertragungsempfänger hat die Ausführung seiner
onReceive-Methode nicht innerhalb eines angemessenen Zeitraums abgeschlossen. - Ein Übertragungsempfänger ruft
goAsyncauf, aber nichtfinishfür dasPendingResult-Objekt.
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 ein ViewModel (unter Nutzung der Leistungsfähigkeit von Kotlin-Koroutinen, ‑Bereichen und ‑Dispatchern) delegieren, wenn die Aufgabe voraussichtlich höchstens einige Sekunden dauert, an einen beliebigen Typ von State Holder oder an WorkManager für Aufgaben, die voraussichtlich länger als einige Sekunden dauern.
GameActivity
Die GameActivity-Bibliothek hat die Anzahl der ANRs in Fallstudien von Spielen und Apps, die in C oder C++ geschrieben sind, reduziert. Wenn Sie Ihre vorhandene native Aktivität durch GameActivity ersetzen, können Sie das Blockieren des UI-Threads reduzieren und einige ANRs verhindern.
Weitere Informationen zu ANR-Fehlern finden Sie unter Reaktionsfähigkeit Ihrer App aufrechterhalten. Weitere Informationen zu Threads finden Sie unter Bessere Leistung durch Threading.
Zusätzliche Ressourcen
Inhalte ansehen
Empfehlungen für Sie
- Hinweis: Linktext wird angezeigt, wenn JavaScript deaktiviert ist
- Übermäßige Wakeups