Chcę ustawić globalną procedurę obsługi nieprzechwyconych wyjątków dla wszystkich wątków w mojej aplikacji na Androida. Tak więc w mojej Application
podklasie ustawiłem implementację Thread.UncaughtExceptionHandler
jako domyślną obsługę nieprzechwyconych wyjątków.
Thread.setDefaultUncaughtExceptionHandler(
new DefaultExceptionHandler(this));
W mojej implementacji staram się AlertDialog
wyświetlić odpowiedni komunikat wyjątku.
Jednak to nie działa. Zawsze, gdy wyjątek jest zgłaszany dla dowolnego wątku, który nie jest obsługiwany, pojawia się standardowe okno dialogowe domyślnego systemu operacyjnego („Przepraszamy!
Jaki jest prawidłowy i idealny sposób ustawienia domyślnej procedury obsługi nieprzechwyconych wyjątków?
Odpowiedzi:
To wszystko, co musisz zrobić. (Upewnij się, że później zatrzymasz proces - stan może być niepewny).
Pierwszą rzeczą do sprawdzenia jest, czy nadal jest wywoływany program obsługi Androida. Możliwe, że Twoja wersja jest wywoływana, ale kończy się niepowodzeniem, a serwer_systemowy wyświetla ogólne okno dialogowe, gdy zauważy awarię procesu.
Dodaj komunikaty dziennika na górze programu obsługi, aby sprawdzić, czy się tam dostanie. Wydrukuj wynik z getDefaultUncaughtExceptionHandler, a następnie wyślij nieprzechwycony wyjątek, aby spowodować awarię. Obserwuj wyjście logcat, aby zobaczyć, co się dzieje.
źródło
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) iLooper.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(); // 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); } } }
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
źródło
java.lang.RuntimeException: Performing pause of activity that is not resumed
. Wierzę, że kiedy próbuję uruchomić własny looper, system wstrzymuje czynność, która ma się rozpocząć? Nie jestem pewien, ale każda pomoc byłaby mile widziana. DziękiMyślę, że aby wyłączyć to w twojej metodzie uncaughtException (), nie wywołuj previousHandler.uncaughtException (), gdzie parametr previousHandler jest ustawiony przez
previousHandler = Thread.getDefaultUncaughtExceptionHandler();
źródło
FWIW Wiem, że to trochę nie na temat, ale z powodzeniem korzystamy z darmowego planu Crittercism . Oferują również pewne funkcje premium, takie jak obsługa wyjątku, aby aplikacja nie uległa awarii.
W wersji bezpłatnej użytkownik nadal widzi awarię, ale przynajmniej otrzymuję wiadomość e-mail i ślad stosu.
Korzystamy również z wersji na iOS (ale słyszałem od kolegów, że nie jest aż tak dobra).
Oto podobne pytania:
źródło
Nie działa, dopóki nie zadzwonisz
android.os.Process.killProcess(android.os.Process.myPid());
na samym końcu Twojego UncaughtExceptionHandler.
źródło