Ich habe vor langer Zeit die einfache Lösung für die benutzerdefinierte Behandlung von Android-Abstürzen veröffentlicht. Es ist ein wenig hackig, funktioniert aber auf allen Android-Versionen (einschließlich Lollipop).
Zuerst ein bisschen Theorie. Die Hauptprobleme bei der Verwendung des nicht erfassten Ausnahmehandlers in Android sind die Ausnahmen, die im Hauptthread (auch als UI-Thread bezeichnet) ausgelöst werden. Und hier ist warum. Wenn die App gestartet wird, ruft das System die ActivityThread.main- Methode auf, die den Main Looper Ihrer App vorbereitet und startet :
public static void main(String[] args) {
…
…
Looper.prepareMainLooper();
…
Looper.loop();
throw new RuntimeException("Main thread loop unexpectedly exited");
}
Der Hauptschleifer ist für die Verarbeitung der im UI-Thread veröffentlichten Nachrichten verantwortlich (einschließlich aller Nachrichten im Zusammenhang mit dem Rendern und der Interaktion der UI). Wenn eine Ausnahme im UI-Thread ausgelöst wird, wird sie von Ihrem Exception-Handler abgefangen. Da Sie loop()
jedoch keine Methode mehr haben, können Sie dem Benutzer keine Dialoge oder Aktivitäten anzeigen, da niemand mehr übrig ist, um UI-Nachrichten zu verarbeiten für dich.
Die vorgeschlagene Lösung ist recht einfach. Wir führen die Looper.loop
Methode selbst aus und umgeben sie mit einem Try-Catch-Block. Wenn eine Ausnahme abgefangen wird, verarbeiten wir sie wie gewünscht (z. B. starten Sie unsere benutzerdefinierte Berichtsaktivität) und rufen die Looper.loop
Methode erneut auf.
Die folgende Methode demonstriert diese Technik (sie sollte vom Application.onCreate
Listener aufgerufen werden ):
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);
}
}
}
Wie Sie sehen können, wird der nicht erfasste Ausnahmebehandler nur für die Ausnahmen verwendet, die in Hintergrundthreads ausgelöst werden. Der folgende Handler fängt diese Ausnahmen ab und gibt sie an den UI-Thread weiter:
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);
}
});
}
}
Ein Beispielprojekt, das diese Technik verwendet, ist auf meinem GitHub-Repo verfügbar: https://github.com/idolon-github/android-crash-catcher