Moyen idéal pour définir Handler global exception non capturée dans Android

Je veux définir un gestionnaire d’exceptions global non capturé pour tous les threads de mon application Android. Donc, dans ma sous-classe Application j’ai défini une implémentation de Thread.UncaughtExceptionHandler comme gestionnaire par défaut pour les exceptions non Thread.UncaughtExceptionHandler .

 Thread.setDefaultUncaughtExceptionHandler( new DefaultExceptionHandler(this)); 

Dans mon implémentation, j’essaie d’afficher un AlertDialog affichant le 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 manipulé, j’obtiens la boîte de dialog stock-default (“Désolé! -Application-a-arrêté-un dialog inattendu”).

Quelle est la manière correcte et idéale de définir un gestionnaire par défaut pour les exceptions non interceptées?

Cela devrait être tout ce que vous devez faire. (Assurez-vous que le processus s’arrête 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 un dialog 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 blocage. Gardez un œil sur la sortie logcat pour voir ce qui se passe.

J’ai posté la solution simple pour la gestion personnalisée des crashs Android depuis longtemps. C’est un peu pirate mais ça marche 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 capturé dans Android sont fournis avec les exceptions lancées dans le thread principal (ou l’interface utilisateur). Et voici pourquoi. Lorsque l’application démarre, le système appelle la méthode ActivityThread.main qui prépare et lance le boucleur principal de votre application:

 public static void main(Ssortingng[] args) { … … Looper.prepareMainLooper(); … Looper.loop(); throw new RuntimeException("Main thread loop unexpectedly exited"); } 

Le looper principal est responsable du traitement des messages postés dans le thread d’interface utilisateur (y compris tous les messages liés au rendu et à l’interaction de l’interface utilisateur). Si une exception est lancée dans le thread d’interface utilisateur, elle sera interceptée par votre gestionnaire d’exceptions, mais comme vous êtes hors de la méthode loop() , vous ne pourrez afficher aucune boîte de dialog ou activité. traiter les messages de l’interface utilisateur pour vous.

La solution proposée est assez simple. Nous Looper.loop méthode Looper.loop par nous-mêmes et l’ Looper.loop bloc try-catch. Lorsqu’une exception est interceptée, nous la traitons comme nous le souhaitons (par exemple, lancez notre activité de rapport personnalisée) et appelez à nouveau la méthode Looper.loop .

La méthode suivante illustre cette technique (elle doit être appelée à partir de l’écouteur Application.onCreate ):

 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 capturé est utilisé uniquement pour les exceptions lancées dans les threads d’arrière-plan. Le gestionnaire suivant intercepte ces exceptions et les propage au 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 repository GitHub: https://github.com/idolon-github/android-crash-catcher

FWIW Je sais que c’est un peu hors sujet, mais nous avons utilisé le plan libre de Crittercism avec succès. Ils offrent également des fonctionnalités haut de gamme, comme la gestion des exceptions pour que l’application ne se bloque pas.

Dans la version gratuite, l’utilisateur voit toujours le plantage, mais au moins, je reçois le courrier électronique et la trace de la stack.

Nous utilisons également la version iOS (mais mes collègues m’ont dit que ce n’était pas aussi bon).


Voici des questions similaires:

  • Gestionnaire d’exceptions global non capturé -> e-mail me connecter?
  • Est-il possible de créer une sorte de gestionnaire d’exceptions global dans Android?

Je pense que pour désactiver cela dans votre méthode uncaughtException () ne pas appeler previousHandler.uncaughtException () où previousHandler est défini par

 previousHandler = Thread.getDefaultUncaughtExceptionHandler(); 

Cela ne fonctionne pas tant que vous n’appelez pas

 android.os.Process.killProcess(android.os.Process.myPid()); 

à la toute fin de votre UncaughtExceptionHandler.