ANR (Application Not Responding) est une notification système sur Android qui apparaît lorsqu’une application ne répond pas aux entrées pendant 5 secondes. Contrairement aux bugs (erreurs logiques sans blocage de l’interface) et aux lags (ralentissement sans arrêt complet), l’ANR est un échec critique enregistré par le système d’exploitation : Android affiche une boîte de dialogue « L’application ne répond pas » avec la possibilité de fermer ou d’attendre. Selon Android Vitals Documentation, les applications avec un taux d’ANR supérieur à 0,5 % reçoivent une note inférieure sur Google Play et peuvent être masquées des recommandations. Le diagnostic comprend l’analyse de /data/anr/traces.txt, l’utilisation de StrictMode et le profilage du thread principal.
Points clés
ANR (Application Not Responding) est un mécanisme de protection de l’utilisateur sur Android qui se déclenche lorsque l’application cesse de répondre aux entrées. Le système suit le temps de traitement des événements : si BroadcastReceiver ne termine pas onReceive en 10 secondes, Service ne revient pas de onCreate en 20 secondes, ou ContentProvider ne répond pas en 15 secondes — Android génère une ANR.
Lorsqu’une ANR se produit, Android affiche une boîte de dialogue système par-dessus toutes les fenêtres : « L’application ne répond pas. Voulez-vous la fermer ou attendre ? » L’utilisateur peut fermer l’application ou attendre sa récupération. Si les ANR se produisent fréquemment, l’utilisateur désinstalle l’application. Google Play prend en compte le taux d’ANR — le pourcentage de sessions avec ANR — dans ses algorithmes de classement.
iOS n’a pas d’équivalent à l’ANR avec une boîte de dialogue système. Au lieu de cela, Apple utilise Watchdog, qui termine le processus avec le code de sortie 0x8badf00d. L’utilisateur ne voit pas de boîte de dialogue — l’application se ferme simplement sur l’écran d’accueil. Cela rend l’ANR sur Android plus visible pour l’utilisateur, mais donne au système plus d’informations de diagnostic.
L’ANR se produit lorsque le système suit un délai d’expiration pour l’un des quatre types de composants. Chaque composant a sa propre limite de temps.
BroadcastReceiver s’exécute dans le thread principal. Si onReceive lance une requête réseau synchrone, une écriture longue en base de données, ou attend un verrou — une ANR se produit en 10 secondes. Solution : utilisez goAsync() et WorkManager pour le traitement en arrière-plan. Un scénario typique est la réception d’une notification Push de FCM et son enregistrement synchrone dans Room.
Service.onCreate et Service.onStartCommand ont une limite de 20 secondes. Si le service lance une initialisation lourde (chargement de bibliothèques, lecture de configuration depuis le réseau) dans le thread principal — l’ANR est inévitable. Utilisez IntentService (obsolète) ou WorkManager pour une exécution garantie en arrière-plan.
ContentProvider.onCreate s’exécute avant Application.onCreate et a une limite de 15 secondes. Si le fournisseur effectue une migration de base de données, charge des dictionnaires, ou initialise le SDK depuis le réseau — cela provoque une ANR au démarrage de l’application. Solution : initialisation paresseuse, délégation des opérations lourdes à WorkManager.
Android fournit plusieurs outils pour l’analyse des ANR : des journaux système aux bibliothèques spécialisées.
À chaque ANR, Android sauvegarde le fichier /data/anr/traces.txt avec un dump de la pile de tous les threads de l’application. Trouvez le thread « main » — la dernière méthode dans la pile indique la cause. Schémas typiques : Thread.sleep(), InputStream.read(), BinderProxy.transact(). Pour extraire le fichier de l’appareil, utilisez adb avec les privilèges de superutilisateur.
Firebase Crashlytics collecte automatiquement les ANR et les affiche dans le tableau de bord avec des traces. Pour Android 11+, les rapports ANR incluent la pile complète du thread principal. L’intégration nécessite l’ajout d’une dépendance et l’initialisation de FirebaseApp dans Application.onCreate.
CPU Profiler dans Android Studio vous permet d’enregistrer des traces de l’application et de voir quelles méthodes consomment du temps CPU. Activez « Record with method traces » et reproduisez le scénario qui provoque l’ANR. La chronologie montrera quelles méthodes s’exécutaient dans le thread principal au moment du blocage.
Exemple d’intégration de Firebase Crashlytics pour la collecte des ANR sur Android :
class App : Application() {
override fun onCreate() {
super.onCreate()
FirebaseApp.initializeApp(this)
FirebaseCrashlytics.getInstance()
.setCrashlyticsCollectionEnabled(true)
StrictMode.setThreadPolicy(StrictMode.ThreadPolicy.Builder()
.detectAll()
.penaltyLog()
.build())
}
}
Corriger l’ANR signifie avant tout déplacer toutes les opérations longues du thread principal vers des threads d’arrière-plan. Examinons des techniques spécifiques pour chaque type de composant.
WorkManager est la solution recommandée par Google pour le travail en arrière-plan. Il garantit l’exécution des tâches dans un thread d’arrière-plan en tenant compte de l’état de l’appareil. Contrairement à Service, WorkManager ne bloque pas le thread principal et résiste aux redémarrages de l’application. Pour BroadcastReceiver, utilisez goAsync() et transmettez le PendingResult à WorkManager.
Exécutez toutes les requêtes réseau, les opérations de base de données et les E/S de fichiers avec Dispatchers.IO. Le thread principal doit seulement mettre à jour l’interface. Utilisez viewModelScope pour l’annulation automatique des coroutines lorsque l’Activity est détruite. Évitez runBlocking() dans tout contexte — il bloque de manière synchrone le thread actuel.
Si ContentProvider effectue une initialisation lente, utilisez un mécanisme de chargement paresseux : créez un fournisseur qui renvoie les données immédiatement et lancez l’initialisation lourde via WorkManager avec un délai. Cela évite les ANR au démarrage de l’application, lorsque le système est le plus sensible aux retards.
Exemple d’utilisation correcte de BroadcastReceiver avec goAsync sur Android :
class FcmReceiver : BroadcastReceiver() {
override fun onReceive(context: Context?, intent: Intent?) {
val pendingResult = goAsync()
WorkManager.getInstance(context!!)
.enqueue(OneTimeWorkRequest.from(NotificationWorker::class.java))
pendingResult.finish()
}
}
La meilleure façon de lutter contre les ANR est de les prévenir pendant le développement grâce à des outils et des décisions architecturales.
StrictMode avec les politiques detectNetwork() et detectDiskReads()/detectDiskWrites() activées identifie les ANR potentielles pendant le développement. Dans les builds Debug, définissez penaltyDeath — toute violation entraînera un crash immédiat et le développeur verra le problème avant le commit.
Firebase Performance suit le temps d’exécution des opérations clés et montre quels scénarios dépassent le seuil d’ANR. Configurez des traces personnalisées pour chaque écran et requête réseau. Si le temps d’exécution dépasse 3 secondes — c’est une ANR potentielle nécessitant une optimisation.
Simulez des conditions lentes : limitez la vitesse du réseau avec Network Link Conditioner sur iOS ou Android Emulator. Ralentissez la lecture du disque en émulant une mémoire lente. ANR se manifeste souvent précisément dans ces conditions ; sur les appareils de développement rapides, elles sont invisibles.
Foire aux questions
Android suit explicitement le temps de traitement des événements sur le thread principal et affiche une boîte de dialogue ANR. iOS utilise Watchdog, qui ferme de force l’application lorsqu’elle se bloque pendant plus de 10–20 secondes. L’ANR est une caractéristique de l’architecture Android où plusieurs composants (BroadcastReceiver, Service) ont des délais d’expiration stricts.
Sur Android 11+, vous pouvez obtenir le dump ANR via adb shell dumpsys dropbox --print data_app_anr. Sur Android 10 et versions antérieures, sans accès root à /data/anr/traces.txt. Utilisez Firebase Crashlytics — il collecte les rapports ANR automatiquement pour Android 11+.
Google Play recommande un taux d’ANR inférieur à 0,5 % — pas plus de 5 ANR pour 1000 sessions. Une application avec un taux supérieur à 1 % reçoit un avertissement dans la console Google Play et peut être masquée des recommandations. Idéalement, le taux d’ANR devrait être inférieur à 0,1 %.
Une coroutine en elle-même ne bloque pas le thread. Mais si à l’intérieur d’une coroutine vous exécutez runBlocking sur le thread principal ou si la coroutine est lancée avec Dispatchers.Main et effectue une longue opération CPU — cela provoquera une ANR. Utilisez Dispatchers.IO pour les E/S et Dispatchers.Default pour les calculs.
Utilisez Android Emulator avec un profil « Slow Network » ou écrivez un test qui appelle Thread.sleep(6000) sur le thread principal. Lancez l’application via Debug et après 5 secondes, vous verrez la boîte de dialogue ANR. Vérifiez que logcat affiche un enregistrement ANR avec une trace.
Résumé
Nous développerons une application mobile clé en main
IT Sectr crée des applications iOS et Android pour les startups et les entreprises depuis 2017. Nous vous conseillerons et vous proposerons la meilleure solution.