Existe-t-il un moyen de savoir où mon application a lancé un ANR (Application Not Responding). J'ai jeté un coup d'oeil au fichier traces.txt dans/data et je vois une trace pour mon application. C'est ce que je vois dans la trace.
DALVIK THREADS:
"main" prio=5 tid=3 TIMED_WAIT
| group="main" sCount=1 dsCount=0 s=0 obj=0x400143a8
| sysTid=691 Nice=0 sched=0/0 handle=-1091117924
at Java.lang.Object.wait(Native Method)
- waiting on <0x1cd570> (a Android.os.MessageQueue)
at Java.lang.Object.wait(Object.Java:195)
at Android.os.MessageQueue.next(MessageQueue.Java:144)
at Android.os.Looper.loop(Looper.Java:110)
at Android.app.ActivityThread.main(ActivityThread.Java:3742)
at Java.lang.reflect.Method.invokeNative(Native Method)
at Java.lang.reflect.Method.invoke(Method.Java:515)
at com.Android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.Java:739)
at com.Android.internal.os.ZygoteInit.main(ZygoteInit.Java:497)
at dalvik.system.NativeStart.main(Native Method)
"Binder Thread #3" prio=5 tid=15 NATIVE
| group="main" sCount=1 dsCount=0 s=0 obj=0x434e7758
| sysTid=734 Nice=0 sched=0/0 handle=1733632
at dalvik.system.NativeStart.run(Native Method)
"Binder Thread #2" prio=5 tid=13 NATIVE
| group="main" sCount=1 dsCount=0 s=0 obj=0x433af808
| sysTid=696 Nice=0 sched=0/0 handle=1369840
at dalvik.system.NativeStart.run(Native Method)
"Binder Thread #1" prio=5 tid=11 NATIVE
| group="main" sCount=1 dsCount=0 s=0 obj=0x433aca10
| sysTid=695 Nice=0 sched=0/0 handle=1367448
at dalvik.system.NativeStart.run(Native Method)
"JDWP" daemon prio=5 tid=9 VMWAIT
| group="system" sCount=1 dsCount=0 s=0 obj=0x433ac2a0
| sysTid=694 Nice=0 sched=0/0 handle=1367136
at dalvik.system.NativeStart.run(Native Method)
"Signal Catcher" daemon prio=5 tid=7 RUNNABLE
| group="system" sCount=0 dsCount=0 s=0 obj=0x433ac1e8
| sysTid=693 Nice=0 sched=0/0 handle=1366712
at dalvik.system.NativeStart.run(Native Method)
"HeapWorker" daemon prio=5 tid=5 VMWAIT
| group="system" sCount=1 dsCount=0 s=0 obj=0x4253ef88
| sysTid=692 Nice=0 sched=0/0 handle=1366472
at dalvik.system.NativeStart.run(Native Method)
----- end 691 -----
Comment puis-je savoir où est le problème? Les méthodes de la trace sont toutes des méthodes SDK.
Merci.
Un ANR se produit lorsqu'une opération longue a lieu dans le thread "principal". Il s’agit du thread de la boucle d’événement. S'il est occupé, Android ne peut plus traiter d’événements graphiques dans l’application, ce qui entraîne le lancement d’une boîte de dialogue ANR.
Maintenant, dans le suivi que vous avez posté, le fil principal semble bien se passer, il n’ya pas de problème. Il est inactif dans MessageQueue, dans l'attente d'un autre message. Dans votre cas, l'ANR était probablement une opération plus longue, et non quelque chose qui bloquait le thread de manière permanente; après l'ANR.
Il est facile de détecter où se produisent les ANR s’il s’agit d’un blocage permanent (impasse pour l’acquisition de certains verrous, par exemple), mais plus difficile s’il s’agit d’un retard temporaire. Tout d’abord, examinez votre code et recherchez les zones vulnérables et les opérations de longue durée. Les exemples peuvent inclure l'utilisation de sockets, verrous, mises en veille de threads et autres opérations de blocage à partir du thread d'événement. Vous devez vous assurer que tout cela se passe dans des threads séparés. Si rien ne semble vous poser problème, utilisez DDMS et activez la vue des discussions. Cela montre tous les threads de votre application similaires à la trace que vous avez. Reproduisez l'ANR et actualisez le thread principal en même temps. Cela devrait vous montrer précisément ce qui se passe au moment de l'ANR
Vous pouvez activer StrictMode dans les API de niveau 9 et supérieur.
StrictMode est le plus souvent utilisé pour attraper un disque ou un réseau accidentel accès sur le thread principal de l'application, où les opérations de l'interface utilisateur sont reçu et animations ont lieu. En gardant le fil conducteur de votre application réactif, vous empêchez également d'empêcher l'affichage des dialogues ANR aux utilisateurs.
public void onCreate() {
StrictMode.setVmPolicy(new StrictMode.VmPolicy.Builder()
.detectAll()
.penaltyLog()
.penaltyDeath()
.build());
super.onCreate();
}
en utilisant
penaltyLog()
, vous pouvez regarder la sortie de adb logcat pendant que vous Utilisez votre application pour voir les violations au fur et à mesure.
Vous vous demandez quelle tâche est responsable d'un thread d'interface utilisateur. Le fichier de trace vous donne un indice pour trouver la tâche. vous devez rechercher un état de chaque thread
Concentrez-vous sur l'état SUSPENDED, MONITOR. L'état du moniteur indique quel thread est étudié et l'état SUSPENDED du thread est probablement la raison principale du blocage.
la trace ne contient pas toujours "en attente de verrouillage". dans ce cas, il est difficile de trouver la raison principale.
J'apprenais Android depuis quelques mois, alors je suis loin d'être un expert, mais j'ai été vraiment déçu de la documentation sur les ANR.
La plupart des conseils semblent viser à les éviter ou à les corriger en regardant à l'aveugle dans votre code, ce qui est génial, mais je n'ai rien trouvé sur l'analyse de la trace.
Il y a trois choses que vous devez vraiment rechercher avec les journaux ANR.
1) Deadlocks: Quand un thread est dans l'état WAIT, vous pouvez parcourir les détails pour trouver qui il est "heldby =". La plupart du temps, cela se tiendra tout seul, mais s'il est tenu par un autre fil, c'est probablement un signe de danger. Allez regarder ce fil et voir ce qui le retient. Vous pourriez trouver une boucle, ce qui est un signe clair que quelque chose ne va pas. C'est assez rare, mais c'est le premier point parce que quand ça arrive, c'est un cauchemar
2) Thread principal en attente: Si votre thread principal est dans l'état WAIT, vérifiez s'il est maintenu par un autre thread. Cela ne devrait pas arriver, car votre thread d'interface utilisateur ne devrait pas être tenu par un thread d'arrière-plan.
Ces deux scénarios signifient que vous devez retravailler votre code de manière significative.
3) Opérations lourdes sur le thread principal: C’est la cause la plus courante d’ANR, mais elle est parfois l’une des plus difficiles à trouver et à corriger. Regardez les détails du fil principal. Faites défiler la trace de la pile jusqu'à ce que vous voyiez les classes que vous reconnaissez (à partir de votre application). Examinez les méthodes de la trace et déterminez si vous passez des appels réseau, des appels de base de données, etc. à ces endroits.
Enfin, et je vous prie de m'excuser d'avoir branché mon propre code sans vergogne, vous pouvez utiliser l'analyseur de journaux python que j'ai écrit à l'adresse suivante: https://github.com/HarshEvilGeek/Android-Log-Analyzer Ceci passera par vos fichiers journaux, ouvrez Fichiers ANR, trouver des blocages, trouver les threads principaux en attente, trouver des exceptions non interceptées dans les journaux de votre agent et les afficher à l'écran de manière relativement facile à lire. Lisez le fichier Lisez-moi (que je suis sur le point d’ajouter) pour savoir comment l’utiliser. Ça m'a aidé beaucoup la semaine dernière!
Lorsque vous analysez des problèmes de minutage, le débogage n’aide généralement pas, car geler l’application à un point d’interruption fera disparaître le problème.
Votre meilleur choix est d'insérer de nombreux appels de journalisation (Log.XXX ()) dans les différents threads et rappels de l'application et de voir où en est le délai. Si vous avez besoin d'un stacktrace, créez une nouvelle exception (instanciez-en une) et enregistrez-la.
Généralement, le système affiche un ANR si une application ne peut pas répondre aux entrées de l'utilisateur.
Dans toutes les situations dans lesquelles votre application effectue une opération potentiellement longue, vous ne devez pas effectuer le travail sur le thread d'interface utilisateur, mais créer un thread de travail et y effectuer l'essentiel du travail. Cela maintient le thread d'interface utilisateur (qui pilote la boucle d'événements de l'interface utilisateur) et empêche le système de conclure que votre code est gelé.
Les applications Android fonctionnent normalement entièrement sur un seul thread, par défaut le "thread d'interface utilisateur" ou "thread principal"). Cela signifie que tout ce que votre application fait dans le thread d'interface utilisateur qui prend beaucoup de temps peut déclencher le dialogue ANR car votre application ne se donne pas la possibilité de gérer l'événement d'entrée ou les diffusions d'intention.
Par conséquent, toute méthode qui s'exécute dans le thread d'interface utilisateur doit faire le moins de travail possible sur ce thread. En particulier, les activités doivent mettre en place le moins possible de méthodes de cycle de vie clés telles que onCreate () et onResume (). Les opérations potentiellement longues telles que les opérations réseau ou de base de données, ou les calculs coûteux tels que le redimensionnement des bitmaps doivent être effectués dans un thread de travail (ou dans le cas d'opérations de bases de données, via une requête asynchrone).
private class DownloadFilesTask extends AsyncTask<URL, Integer, Long> {
// Do the long-running work in here
protected Long doInBackground(URL... urls) {
int count = urls.length;
long totalSize = 0;
for (int i = 0; i < count; i++) {
totalSize += Downloader.downloadFile(urls[i]);
publishProgress((int) ((i / (float) count) * 100));
// Escape early if cancel() is called
if (isCancelled()) break;
}
return totalSize;
}
// This is called each time you call publishProgress()
protected void onProgressUpdate(Integer... progress) {
setProgressPercent(progress[0]);
}
// This is called when doInBackground() is finished
protected void onPostExecute(Long result) {
showNotification("Downloaded " + result + " bytes");
}
}
Pour exécuter ce thread de travail, créez simplement une instance et appelez execute ():
new DownloadFilesTask().execute(url1, url2, url3);
http://developer.Android.com/training/articles/perf-anr.html
Vous devez rechercher "en attente de verrouillage" dans le fichier /data/anr/traces.txt
pour plus de détails: Engineer for High Performance avec les outils d'Android & Play (Google I/O '17)
mon problème avec ANR, après beaucoup de travail, j'ai découvert qu'un fil appelait une ressource qui n'existait pas dans la présentation, au lieu de renvoyer une exception, j'ai obtenu ANR ...
Pensez à utiliser la bibliothèque ANR-Watchdog pour suivre et capturer avec précision les traces de pile ANR avec un niveau de détail élevé. Vous pouvez ensuite les envoyer à votre bibliothèque de rapports d'incidents. Je recommande d'utiliser setReportMainThreadOnly()
dans ce scénario. Vous pouvez soit faire en sorte que l'application jette une exception non fatale au point de gel, ou obliger l'application à quitter de force lorsque l'ANR se produit.
Notez que les rapports ANR standard envoyés à votre console de développeur Google Play ne sont souvent pas assez précis pour identifier le problème exact. C'est pourquoi une bibliothèque tierce est nécessaire.
Sur la base de @Horyun Lee, j’ai écrit un petit script python pour aider à étudier l’ANR à partir de traces.txt
.
Les ANR seront générés sous forme de graphiques par graphviz
si vous avez installé grapvhviz
sur votre système.
$ ./anr.py --format png ./traces.txt
Un png sortira comme ci-dessous si des ANR sont détectés dans le fichier traces.txt
. C'est plus intuitif.
Le fichier d'exemple traces.txt
utilisé ci-dessus a été extrait de here .