Я давно опубликовал простое решение для пользовательской обработки сбоев Android. Это немного взломано, но работает на всех версиях Android (включая Lollipop).
Сначала немного теории. Основные проблемы, возникающие при использовании обработчика неперехваченных исключений в Android, связаны с исключениями, возникающими в основном (также известном как пользовательский интерфейс) потоке. И вот почему. Когда приложение запускается, система вызывает метод ActivityThread.main, который подготавливает и запускает главный цикл вашего приложения:
public static void main(String[] args) {
…
…
Looper.prepareMainLooper();
…
Looper.loop();
throw new RuntimeException("Main thread loop unexpectedly exited");
}
Главный лупер отвечает за обработку сообщений, размещенных в потоке пользовательского интерфейса (включая все сообщения, связанные с отображением и взаимодействием пользовательского интерфейса). Если в потоке пользовательского интерфейса выбрасывается исключение, оно будет перехвачено вашим обработчиком исключений, но, поскольку вы не работаете, loop()
вы не сможете показывать пользователю какие-либо диалоги или действия, поскольку некому обрабатывать сообщения пользовательского интерфейса. для тебя.
Предлагаемое решение довольно простое. Мы запускаем Looper.loop
метод самостоятельно и окружаем его блоком try-catch. Когда исключение обнаружено, мы обрабатываем его так, как хотим (например, запускаем действие нашего настраиваемого отчета) и Looper.loop
снова вызываем метод.
Следующий метод демонстрирует эту технику (он должен вызываться из Application.onCreate
слушателя):
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);
}
}
}
Как видите, обработчик неперехваченных исключений используется только для исключений, созданных в фоновых потоках. Следующий обработчик перехватывает эти исключения и передает их в поток пользовательского интерфейса:
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);
}
});
}
}
Пример проекта, в котором используется этот метод, доступен в моем репозитории GitHub: https://github.com/idolon-github/android-crash-catcher.