Lorsque le thread UI d'une application Android est bloqué trop longtemps, une erreur ANR (« L'application ne répond pas ») se déclenche. Si l'application est exécutée au premier plan, le système affiche une boîte de dialogue, comme illustré dans la figure 1. La boîte de dialogue ANR permet à l'utilisateur de forcer la fermeture de l'application.
Les ANR posent problème, car le thread principal de l'application, responsable de la mise à jour de l'UI, ne peut pas traiter les événements d'entrée utilisateur ni dessiner, ce qui génère de la frustration pour l'utilisateur. Pour en savoir plus sur le thread principal de l'application, consultez Présentation des processus et des threads.
Une erreur ANR se déclenche pour votre application lorsque l'une des conditions suivantes se produit :
- Délai d'envoi des entrées dépassé : si votre application n'a pas répondu à une entrée (comme un appui sur une touche ou un événement tactile sur l'écran) dans les cinq secondes.
- Exécution du service : si un service déclaré par votre application ne peut pas terminer l'exécution de
Service.onCreateetService.onStartCommand/Service.onBinden quelques secondes. Service.startForegroundnon appelé : si votre application utiliseContext.startForegroundServicepour démarrer un nouveau service au premier plan, mais que le service n'appelle passtartForegrounddans les cinq secondes.- Diffusion de l'intent : si l'exécution d'un
BroadcastReceivern'est pas terminée dans un délai donné. Si l'application présente une activité au premier plan, ce délai est de cinq secondes. - Interactions
JobScheduler: si unJobServicene renvoie pas une valeur deJobService.onStartJobouJobService.onStopJobdans les secondes qui suivent, ou si une tâche lancée par l'utilisateur démarre et que votre application n'appelle pasJobService.setNotificationdans les quelques secondes suivant l'appel deJobService.onStartJob. Pour les applications ciblant Android 13 et les versions antérieures, les erreurs ANR sont silencieuses et ne sont pas signalées à l'application. Pour les applications ciblant Android 14 et versions ultérieures, les erreurs ANR sont explicites et sont signalées à l'application.
Si votre application rencontre des erreurs ANR, vous pouvez suivre les instructions de ce document pour les diagnostiquer et les résoudre.
Diagnostiquer les erreurs ANR
Voici quelques tendances courantes à prendre en compte lors du diagnostic des ANR :
- L'application effectue des opérations lentes impliquant des E/S sur le thread principal.
- L'application effectue un calcul long sur le thread principal.
- Le thread principal effectue un appel de liaison synchrone vers un autre processus, et le retour de cet autre processus prend beaucoup de temps.
- Le thread principal est bloqué en attendant un blocage synchronisé pour une longue opération qui se produit sur un autre thread.
- Le thread principal se trouve dans un interblocage avec un autre thread, soit au cours de votre processus, soit via un appel de liaison. Le thread principal n'attend pas que l'opération longue se termine. Il se trouve dans une situation d'interblocage.
Les techniques suivantes peuvent vous aider à déterminer la cause de vos erreurs ANR.
HealthStats
HealthStats fournit des métriques sur l'état d'une application en capturant le temps système et utilisateur total, le temps CPU, le réseau, les métriques radio, le temps d'activation/de désactivation de l'écran et les alarmes de réveil. Cela peut vous aider à mesurer l'utilisation globale du processeur et la décharge de la batterie.
Déboguer
Debug vous aide à inspecter les applications Android pendant le développement, y compris le traçage et le nombre d'allocations pour identifier les à-coups et la latence dans les applications.
Vous pouvez également utiliser Debug pour obtenir des compteurs d'exécution et de mémoire native, ainsi que des métriques de mémoire qui peuvent vous aider à identifier l'espace mémoire utilisé d'un processus particulier.
ApplicationExitInfo
ApplicationExitInfo est disponible sur Android 11 (niveau d'API 30) ou version ultérieure et fournit des informations sur le motif de fermeture d'une application. Cela inclut les erreurs ANR, une mémoire insuffisante, les plantages d'application, l'utilisation excessive du processeur, les interruptions utilisateur, les interruptions système et les modifications des autorisations d'exécution.
Mode strict
StrictMode vous aide à détecter les opérations d'E/S accidentelles sur le thread principal pendant le développement de votre appli. Vous pouvez utiliser StrictMode au niveau de l'application ou de l'activité.
Activer les boîtes de dialogue ANR en arrière-plan
Android affiche des boîtes de dialogue ANR pour les applications qui mettent trop de temps à traiter le message de diffusion uniquement si l'option Afficher toutes les erreurs ANR est activée dans les Options pour les développeurs de l'appareil. Pour cette raison, les boîtes de dialogue ANR en arrière-plan ne sont pas toujours présentées à l'utilisateur, même lorsque l'application rencontre des problèmes de performances.
Goulots d'étranglement de la recomposition
Utilisez le Profileur Android Studio et l'outil d'inspection de la mise en page pour identifier les goulots d'étranglement de la recomposition. Pour en savoir plus, consultez Performances de Jetpack Compose.
Récupérer un fichier de traces
Android stocke les informations de trace en cas d'erreur ANR. Pour les versions d'OS plus anciennes, un seul fichier /data/anr/traces.txt est installé sur l'appareil. Dans les versions d'OS plus récentes, il existe plusieurs fichiers /data/anr/anr_*. Vous pouvez accéder aux traces ANR d'un appareil ou d'un émulateur en utilisant Android Debug Bridge (adb) en tant que racine :
adb root
adb shell ls /data/anr
adb pull /data/anr/<filename>
Vous pouvez générer un rapport de bug à partir d'un appareil physique à l'aide de l'option pour les développeurs "Créer un rapport de bug" sur l'appareil ou de la commande adb bugreport sur votre ordinateur de développement. Pour en savoir plus, consultez Capturer et lire les rapports de bug.
Résoudre les problèmes
Une fois que vous avez identifié le problème, vous pouvez utiliser les conseils de cette section pour le résoudre.
Lenteur du code dans le thread principal
Identifiez les emplacements de votre code où le thread principal de l'application est occupé pendant plus de cinq secondes. Recherchez les cas d'utilisation suspects dans votre application et essayez de reproduire l'erreur ANR.
Un problème courant est une tâche de longue durée directement dans un 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/S sur le thread principal
L'exécution d'opérations d'E/S sur le thread principal est une cause fréquente de lenteur, ce qui peut entraîner des erreurs ANR. Dans Compose, les développeurs déclenchent souvent accidentellement des lectures de disque (comme SharedPreferences ou des appels de base de données) lorsqu'ils tentent de dériver l'état initial.
Exécutez les opérations d'E/S de longue durée en dehors de la couche UI. Utilisez withContext(Dispatchers.IO) dans un ViewModel ou, mieux encore, utilisez un Repository dans la couche de données.
Interblocages
Un interblocage se produit lorsqu'un thread passe à l'état d'attente, car une ressource requise est détenue par un autre thread, qui attend également une ressource détenue par le premier thread. Si le thread principal de l'application se trouve dans cette situation, il est probable que des erreurs ANR se produisent.
Les interblocages sont un phénomène bien étudié en informatique. Il existe des algorithmes de prévention des interblocages que vous pouvez utiliser pour éviter ce problème.
Pour en savoir plus, consultez les articles sur l'interblocage et les algorithmes de prévention des interblocages sur Wikipédia.
Lorsque vous utilisez Kotlin et Compose, vous pouvez remplacer les verrous primitifs par des Mutex de coroutine non bloquants (Mutex.withLock) pour éviter le blocage des threads en suspendant le contexte d'exécution au lieu de geler le thread d'UI. Exemple :
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()
}
}
}
Broadcast receivers lents
Les applications peuvent répondre aux messages de diffusion, par exemple en activant ou en désactivant le mode Avion, ou en cas de changement d'état de la connectivité, à l'aide de broadcast receivers. Une erreur ANR se produit lorsqu'une application prend trop de temps pour traiter le message de diffusion.
Une erreur ANR se produit dans les cas suivants :
- Un broadcast receiver n'a pas fini d'exécuter sa méthode
onReceivedans un délai considérable. - Un broadcast receiver appelle
goAsyncet n'appelle pasfinishsur l'objetPendingResult.
Votre application ne doit effectuer des opérations courtes que dans la méthode onReceive d'un BroadcastReceiver. Toutefois, si votre application nécessite un traitement plus complexe à la suite d'un message de diffusion, vous devez reporter la tâche vers un ViewModel (en tirant parti de la puissance des coroutines, des portées et des répartiteurs Kotlin) si la tâche devrait prendre quelques secondes au maximum, vers n'importe quel type de détenteur d'état ou vers WorkManager pour les tâches qui devraient prendre plus de quelques secondes.
GameActivity
La bibliothèque GameActivity a réduit le nombre d'erreurs ANR dans les études de cas de jeux et d'applications écrits en C ou C++. Si vous remplacez votre activité native existante par GameActivity, vous pouvez réduire le blocage des threads UI et empêcher certaines erreurs ANR.
Pour en savoir plus sur les erreurs ANR, consultez Garder une application responsive. Pour en savoir plus sur les threads, consultez Améliorer les performances grâce à l'exécution de threads.
Ressources supplémentaires
Afficher le contenu
Recommandations personnalisées
- Remarque : Le texte du lien s'affiche lorsque JavaScript est désactivé
- Nombre excessif de wakeups