Идеальный способ установить глобальный обработчик необработанных исключений в Android - PullRequest
83 голосов
/ 04 мая 2010

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

Thread.setDefaultUncaughtExceptionHandler(
                new DefaultExceptionHandler(this));

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

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

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

Ответы [ 5 ]

24 голосов
/ 05 мая 2010

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

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

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

11 голосов
/ 24 января 2015

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

Сначала немного теории. Основные проблемы, возникающие при использовании обработчика необработанных исключений в Android, связаны с исключениями, генерируемыми в основном потоке (он же 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 голосов
/ 28 августа 2012

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

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

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


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

3 голосов
/ 04 мая 2010

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

previousHandler = Thread.getDefaultUncaughtExceptionHandler();
1 голос
/ 26 февраля 2014

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

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

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...