Już dawno opublikowałem proste rozwiązanie do niestandardowej obsługi awarii Androida. Jest trochę hacky, ale działa na wszystkich wersjach Androida (w tym Lollipop).
Najpierw trochę teorii. Główne problemy występujące podczas korzystania z modułu obsługi nieprzechwyconych wyjątków w systemie Android obejmują wyjątki zgłaszane w głównym wątku (znanym również jako UI). A oto dlaczego. Gdy aplikacja uruchamia się, system wywołuje metodę ActivityThread.main , która przygotowuje i uruchamia główny pętlę Twojej aplikacji:
public static void main(String[] args) {
…
…
Looper.prepareMainLooper();
…
Looper.loop();
throw new RuntimeException("Main thread loop unexpectedly exited");
}
Główny looper jest odpowiedzialny za przetwarzanie komunikatów publikowanych w wątku UI (w tym wszystkich komunikatów związanych z renderowaniem i interakcją UI). Jeśli wyjątek zostanie zgłoszony w wątku interfejsu użytkownika, zostanie on przechwycony przez moduł obsługi wyjątków, ale ponieważ nie masz loop()
metody, nie będziesz w stanie pokazać użytkownikowi żadnego okna dialogowego ani działania, ponieważ nie ma już nikogo do przetwarzania komunikatów interfejsu użytkownika dla Was.
Zaproponowane rozwiązanie jest dość proste. Uruchamiamy Looper.loop
metodę samodzielnie i otaczamy ją blokiem try-catch. Kiedy wyjątek zostanie przechwycony, przetwarzamy go tak, jak chcemy (na przykład rozpoczynamy naszą niestandardową aktywność raportu) i Looper.loop
ponownie wywołujemy metodę.
Poniższa metoda demonstruje tę technikę (należy ją wywołać ze Application.onCreate
słuchacza):
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);
}
}
}
Jak widać, procedura obsługi nieprzechwyconych wyjątków jest używana tylko dla wyjątków zgłaszanych w wątkach w tle. Następująca procedura obsługi przechwytuje te wyjątki i propaguje je do wątku interfejsu użytkownika:
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);
}
});
}
}
Przykładowy projekt wykorzystujący tę technikę jest dostępny na moim repozytorium GitHub: https://github.com/idolon-github/android-crash-catcher