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


88

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

Thread.setDefaultUncaughtExceptionHandler(
                new DefaultExceptionHandler(this));

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

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

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


1
Не могли бы вы поделиться кодом для того же ...
Code_Life

2
Если вы хотите , чтобы войти ваши исключения, посмотрите на acra.ch . ACRA позволяет отправлять отчеты об ошибках в Google-Doc или вам по электронной почте.
Александр Паша

1
@Alexander Или вы можете просто использовать Google Analytics для Android и регистрировать все исключения, которые хотите ...
Игорь Ганапольский

Ответы:


24

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

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

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


10
«выброс неперехваченного исключения, вызывающего сбой после обработки ошибки» по-прежнему важен. Я только что испытал это. Мое приложение было заблокировано после того, как я обработал исключение и не генерировал неперехваченное исключение.
OneWorld,

@OneWorld Jepp здесь то же самое - по крайней мере, в части блокировки - похоже, нет никакого способа «спасти» приложение от сбоя.
AgentKnopf

@Zainodis Я опубликовал ответ на этот вопрос, не относящийся к теме, со ссылкой на Crittercism - я думаю, что у них есть функция, которая позволяет вам все-таки «спасти» приложение от сбоев. Не уверен - я использую только бесплатную версию atm.
Ричард Ле Мезурье,

@RichardLeMesurier Спасибо за подсказку - проверю :)!
AgentKnopf

Странный!!! uncaughtexception вызывается, даже если я обрабатываю исключение в своей деятельности. Любая идея.
Hiren Dabhi

12

Я давно опубликовал простое решение для пользовательской обработки сбоев 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();

    // 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.


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

Привет, пока это работает для перехвата неперехваченных исключений, но по какой-то причине этот код всегда выдает исключения. Сначала я думал, что это из-за строки RuntimeException, которая есть в методе startCatcher, но после ее удаления я все еще получаю исключение. Я не уверен, что это обязательно. Во всяком случае, я получаю исключение java.lang.RuntimeException: Performing pause of activity that is not resumed. Я считаю, что когда я пытаюсь запустить свой собственный лупер, система приостанавливает действие, которое вот-вот начнется? Я не уверен, но любая помощь будет оценена по достоинству. Спасибо
sttaq

также, если я удалю startCatcher, т.е. запустил приложение без вашего кода, все будет работать нормально без каких-либо исключений.
sttaq

@sttaq Какую версию Android вы используете?
Idolon

Думаю, я пробовал это на 2.3.x
sttaq

3

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

previousHandler = Thread.getDefaultUncaughtExceptionHandler();

2

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

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

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


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


1

Не работает пока ты не позвонишь

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

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

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.