Идеальный способ установки глобального неотображаемого обработчика исключений в Android

Я хочу установить глобальный обработчик исключенных исключений для всех потоков в приложении для Android. Итак, в моем подклассе Application я установил реализацию Thread.UncaughtExceptionHandler как обработчик по умолчанию для неперехваченных исключений.

Thread.setDefaultUncaughtExceptionHandler(
                new DefaultExceptionHandler(this));

В моей реализации я пытаюсь показать AlertDialog отображение соответствующего сообщения об исключении.

Однако это не работает. Всякий раз, когда вызывается исключение для любого потока, который не обрабатывается, я получаю запас, диалог по умолчанию ОС ( "Извините! -Application-has-stop-неожиданный диалог" ).

Каков правильный и идеальный способ установки обработчика по умолчанию для неперехваченных исключений?

Ответ 1

Это должно быть все, что вам нужно. (Убедитесь, что вы заставляете процесс останавливаться после этого - все может быть в неопределенном состоянии.)

Первое, что нужно проверить, - это вызов обработчика Android. Возможно, что ваша версия вызывается, но неудачно, и системный_сервер показывает общий диалог, когда видит сбои процесса.

Добавьте несколько сообщений журнала вверху вашего обработчика, чтобы узнать, попадает ли он туда. Распечатайте результат из getDefaultUncaughtExceptionHandler, а затем отбросьте неперехваченное исключение, чтобы вызвать сбой. Следите за выходом logcat, чтобы узнать, что происходит.

Ответ 2

Я опубликовал простое решение для пользовательской обработки Android. Он немного взломан, однако он работает на всех версиях Android (включая Lollipop).

Сначала немного теории. Основные проблемы, связанные с использованием обработчика исключенных обработчиков на Android, включают исключения, которые были выбраны в основном (aka UI) потоке. И вот почему. Когда приложение запускает системные вызовы 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();

    // 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);
        }
    }
}

Как вы можете видеть, обработчик исключенных исключений используется только для исключений, созданных в фоновом потоке. Следующий обработчик ловит эти исключения и распространяет их на поток пользовательского интерфейса:

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

Ответ 3

Я думаю, что отключить это в вашем методе uncaughtException() не вызывать previousHandler.uncaughtException(), где previousHandler задается

previousHandler = Thread.getDefaultUncaughtExceptionHandler();

Ответ 4

FWIW Я знаю, что это немного не по теме, но мы с успехом использовали "Бесплатный критерий" . Они также предлагают некоторые премиальные функции, такие как обработка исключения, поэтому приложение не сбой.

В бесплатной версии пользователь по-прежнему видит сбой, но по крайней мере я получаю электронную почту и трассировку стека.

Мы также используем версию iOS (но я слышал от своих коллег, что это не совсем так).


Вот похожие вопросы:

Ответ 5

Это не работает, пока вы не вызовете

android.os.Process.killProcess(android.os.Process.myPid());

в самом конце вашего UncaughtExceptionHandler.

Ответ 6

Вы можете обработать необработанные исключения с помощью библиотеки FireCrasher и выполнить восстановление из нее.

Вы можете узнать больше о библиотеке в этой средней статье