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();
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