Je souhaite définir un gestionnaire d'exceptions global non intercepté pour tous les threads de mon application Android. Donc, dans ma Application
sous - classe, j'ai défini une implémentation de Thread.UncaughtExceptionHandler
comme gestionnaire par défaut pour les exceptions non interceptées.
Thread.setDefaultUncaughtExceptionHandler(
new DefaultExceptionHandler(this));
Dans mon implémentation, j'essaye d'afficher un AlertDialog
message d'exception approprié.
Cependant, cela ne semble pas fonctionner. Chaque fois qu'une exception est lancée pour un thread qui n'est pas géré, j'obtiens la boîte de dialogue stock, par défaut du système d'exploitation ("Désolé! -L'application-s'est-arrêtée-inopinément dialogue").
Quelle est la manière correcte et idéale de définir un gestionnaire par défaut pour les exceptions non interceptées?
Réponses:
Cela devrait être tout ce que vous avez à faire. (Assurez-vous de provoquer l'arrêt du processus par la suite - les choses pourraient être dans un état incertain.)
La première chose à vérifier est de savoir si le gestionnaire Android est toujours appelé. Il est possible que votre version soit appelée mais échoue fatalement et que le serveur_système affiche une boîte de dialogue générique lorsqu'il voit le processus se bloquer.
Ajoutez des messages de journal en haut de votre gestionnaire pour voir s'il y parvient. Imprimez le résultat de getDefaultUncaughtExceptionHandler, puis lancez une exception non interceptée pour provoquer un plantage. Gardez un œil sur la sortie de logcat pour voir ce qui se passe.
la source
J'ai posté la solution simple pour la gestion personnalisée des plantages Android il y a longtemps. C'est un peu hacky mais cela fonctionne sur toutes les versions d'Android (y compris la Lollipop).
D'abord un peu de théorie. Les principaux problèmes lorsque vous utilisez un gestionnaire d'exceptions non interceptées dans Android viennent avec les exceptions levées dans le thread principal (aka UI). Et voici pourquoi. Lorsque l'application démarre, le système appelle la méthode ActivityThread.main qui prépare et démarre le boucleur principal de votre application:
public static void main(String[] args) { … … Looper.prepareMainLooper(); … Looper.loop(); throw new RuntimeException("Main thread loop unexpectedly exited"); }
Le boucleur principal est responsable du traitement des messages publiés dans le fil de discussion de l'interface utilisateur (y compris tous les messages liés au rendu et à l'interaction de l'interface utilisateur). Si une exception est levée dans le thread de l'interface utilisateur, elle sera interceptée par votre gestionnaire d'exceptions, mais comme vous êtes hors de
loop()
méthode, vous ne pourrez pas afficher de dialogue ou d'activité à l'utilisateur car il ne reste plus personne pour traiter les messages de l'interface utilisateur. pour toi.La solution proposée est assez simple. Nous exécutons la
Looper.loop
méthode par nous-mêmes et l'entourons d'un bloc try-catch. Lorsqu'une exception est interceptée, nous la traitons comme nous le souhaitons (par exemple, nous démarrons notre activité de rapport personnalisé) et appelons àLooper.loop
nouveau la méthode.La méthode suivante illustre cette technique (elle doit être appelée à partir de l'
Application.onCreate
auditeur):private void startCatcher() { UncaughtExceptionHandler systemUncaughtHandler = Thread.getDefaultUncaughtExceptionHandler(); // the following handler is used to catch exceptions thrown in background threads Thread.setDefaultUncaughtExceptionHandler(new UncaughtHandler(new Handler())); while (true) { try { Looper.loop(); Thread.setDefaultUncaughtExceptionHandler(systemUncaughtHandler); throw new RuntimeException("Main thread loop unexpectedly exited"); } catch (Throwable e) { showCrashDisplayActivity(e); } } }
Comme vous pouvez le voir, le gestionnaire d'exceptions non interceptées est utilisé uniquement pour les exceptions levées dans les threads d'arrière-plan. Le gestionnaire suivant intercepte ces exceptions et les propage vers le thread d'interface utilisateur:
static class UncaughtHandler implements UncaughtExceptionHandler { private final Handler mHandler; UncaughtHandler(Handler handler) { mHandler = handler; } public void uncaughtException(Thread thread, final Throwable e) { mHandler.post(new Runnable() { public void run() { throw new BackgroundException(e); } }); } }
Un exemple de projet utilisant cette technique est disponible sur mon référentiel GitHub: https://github.com/idolon-github/android-crash-catcher
la source
java.lang.RuntimeException: Performing pause of activity that is not resumed
. Je crois que lorsque j'essaye de démarrer mon propre looper, le système met en pause l'activité qui est sur le point de démarrer? Je ne suis pas sûr mais toute aide serait appréciée. MerciJe pense que pour désactiver cela dans votre méthode uncaughtException (), n'appelez pas previousHandler.uncaughtException () où previousHandler est défini par
previousHandler = Thread.getDefaultUncaughtExceptionHandler();
la source
FWIW Je sais que c'est un peu hors sujet, mais nous avons utilisé le plan gratuit de Crittercism avec succès. Ils offrent également des fonctionnalités premium, comme la gestion de l'exception pour que l'application ne plante pas.
Dans la version gratuite, l'utilisateur voit toujours le plantage, mais au moins je reçois l'e-mail et la trace de la pile.
Nous utilisons également la version iOS (mais mes collègues me disent qu'elle n'est pas aussi bonne).
Voici des questions similaires:
la source
Ça ne marche pas tant que tu n'appelles pas
android.os.Process.killProcess(android.os.Process.myPid());
à la toute fin de votre UncaughtExceptionHandler.
la source