Une façon idéale de définir global uncaught exception Handler dans Android

je veux définir un gestionnaire d'exception global uncaught pour tous les threads de mon application Android. Ainsi, dans ma sous-classe Application , j'ai défini une implémentation de Thread.UncaughtExceptionHandler comme gestionnaire par défaut pour les exceptions non récupérées.

Thread.setDefaultUncaughtExceptionHandler(
                new DefaultExceptionHandler(this));

dans mon implémentation, j'essaie d'afficher un AlertDialog affichant un message d'exception approprié.

cependant, cela ne semble pas fonctionner. Chaque fois, une exception est lancée pour n'importe quel fil qui va non-traitée, j'ai le stock, le système d'exploitation par défaut de la boîte de dialogue ("Désolé!-Demande-a-arrêté de façon inattendue dialogue").

Quelle est la façon correcte et idéale de définir un gestionnaire par défaut pour les exceptions non récupérées?

81
demandé sur Idolon 2010-05-04 14:12:52

5 réponses

ça devrait être tout ce que vous avez à 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 si le gestionnaire Android est toujours appelé. Il est possible que votre version soit appelée mais qu'elle tombe en panne fatalement et que le system_server affiche un dialogue Générique quand il voit le plantage du processus.

ajoutez des messages de log en haut de votre gestionnaire pour voir si c'est comment y arriver. Imprimer le résultat de getdefaultuncaulaughtexceptionhandler et ensuite lancer une exception uncaught pour causer un crash. Gardez un oeil sur la sortie logcat pour voir ce qui se passe.

23
répondu fadden 2010-05-04 21:04:58

j'ai posté la simple solution pour le traitement personnalisé des accidents Android il ya longtemps. Il est un peu hacky cependant il fonctionne sur toutes les versions Android (y compris la sucette).

d'Abord un peu de théorie. Les principaux problèmes lorsque vous utilisez uncaught exception handler dans Android viennent avec les exceptions lancées dans le fil principal (AKA UI). Et voici pourquoi. Lorsque l'application démarre les appels système ActivityThread.méthode principale qui prépare et démarre le principal looper de votre application:

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

looper principal est responsable du traitement des messages postés dans le thread de L'interface utilisateur (y compris tous les messages relatifs au rendu et à l'interaction de L'interface utilisateur). Si une exception est lancée dans le thread de L'interface utilisateur, elle sera attrapée par votre gestionnaire d'exception, mais puisque vous n'êtes plus dans la méthode loop() , vous ne pourrez pas montrer de dialogue ou d'activité à l'utilisateur car il n'y a plus personne pour traiter L'interface utilisateur. des messages pour vous.

la solution proposée est assez simple. Nous utilisons notre propre méthode Looper.loop et nous l'entourons d'un bloc "try-catch". Quand une exception est attrapée, nous la traitons comme nous le voulons (par exemple démarrer notre activité de rapport personnalisé) et appelons à nouveau la méthode Looper.loop .

la méthode suivante démontre cette technique (elle doit être appelée de l'auditeur 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 handler d'exception uncaught est utilisé seulement pour les exceptions jetées dans les fils de fond. Le gestionnaire suivant saisit ces exceptions et les propage au fil UI:

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 qui utilise cette technique est disponible sur mon github repo: https://github.com/idolon-github/android-crash-catcher

9
répondu Idolon 2017-05-23 11:54:53

FWIW, je sais que c'est un peu hors-sujet, mais nous avons été à l'aide de Crittercism du plan libre avec succès. Ils offrent également certaines fonctionnalités haut de gamme, comme la gestion de l'exception afin que l'application ne plante pas.

dans la version gratuite, l'utilisateur voit toujours le crash, mais au moins je reçois l'email et la trace de la pile.

nous utilisons également la version iOS (mais j'ai entendu de mes collègues qu'elle n'est pas aussi bonne).


Voici des questions similaires:

3
répondu Richard Le Mesurier 2017-05-23 12:18:00

je pense à désactiver que dans votre méthode uncaughtException() n'appelez pas previousHandler.uncaughtException () où previousHandler est défini par

previousHandler = Thread.getDefaultUncaughtExceptionHandler();
3
répondu Robby Pond 2014-12-06 04:24:48

il ne fonctionne pas jusqu'à ce que vous appelez

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

à la toute fin de votre marchandeur.

1
répondu Joseph_Marzbani 2014-12-06 04:25:01