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

Есть ли пример кода или учебное пособие о том, как использовать метод Thread.setDefaultUncaughtExceptionHandler? По сути, я пытаюсь отобразить в моем приложении настраиваемое диалоговое окно с предупреждением, когда возникает исключение. Можно ли сделать это? Я знаю, что немного сложно отобразить что-то на экране, если исключение выдается в потоке пользовательского интерфейса, но я не знаю, как это обойти.

Ответ 1

Основной пример для тех, кто приходит на эту страницу с решением :)

public class ChildActivity extends BaseActivity {
    @SuppressWarnings("unused")
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        int a=1/0;
    }
}

Класс для обработки ошибок:

public class BaseActivity extends Activity{
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        Thread.setDefaultUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() {
            @Override
            public void uncaughtException(Thread paramThread, Throwable paramThrowable) {
                Log.e("Alert","Lets See if it Works !!!");
            }
        });
    }
}

Ответ 2

Здесь вариант от Mohit Sharma со следующими улучшениями:

  • Не вызывает зависание приложения/службы после обработки ошибок.
  • Позволяет Android выполнять обычную обработку ошибок после вашего собственного

код:

public class BaseActivity extends Activity {
    @Override
    public void onCreate() {
        super.onCreate();

        final Thread.UncaughtExceptionHandler oldHandler =
            Thread.getDefaultUncaughtExceptionHandler();

        Thread.setDefaultUncaughtExceptionHandler(
            new Thread.UncaughtExceptionHandler() {
                @Override
                public void uncaughtException(
                    Thread paramThread,
                    Throwable paramThrowable
                ) {
                    //Do your own error handling here

                    if (oldHandler != null)
                        oldHandler.uncaughtException(
                            paramThread,
                            paramThrowable
                        ); //Delegates to Android error handling
                    else
                        System.exit(2); //Prevents the service/app from freezing
                }
            });
    }
}

Ответ 3

Имейте в виду, что параметр The RuntimePermission("setDefaultUncaughtExceptionHandler") проверяется перед установкой обработчика и убедитесь, что вы заставляете процесс останавливаться после этого, бросая неперехваченное исключение, поскольку все может быть в неопределенном состоянии.

Не отображать ничего, действительно, поток пользовательского интерфейса, возможно, был разбит, записывать журнал и/или отправлять данные на сервер. Возможно, вы захотите проверить этот вопрос и его ответы.

Ответ 5

Я просто хотел показать свой опыт до сих пор. Я использую решение, предложенное fooobar.com/questions/129142/... чтобы сбросить исключение в мой файл журнала, прежде чем передать управление обработчику исключений по умолчанию.

Тем не менее, моя структура выглядит так:

          BaseActivity
               |
    _______________________
    |          |          |
Activity A Activity B Activity C
final Thread.UncaughtExceptionHandler defaultEH = Thread.getDefaultUncaughtExceptionHandler();                                                                                                                                                                                                                                                                                                                              
    Thread.setDefaultUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() {                                                                                                                                                                                                                                                                                                                                           
        @Override                                                                                                                                                                                                                                                                                                                                                                                                               
        public void uncaughtException(Thread thread, Throwable e) {                                                                                                                                                                                                                                                                                                                                                             
            handleUncaughtException(thread, e, defaultEH);                                                                                                                                                                                                                                                                                                                                                                      
        }                                                                                                                                                                                                                                                                                                                                                                                                                       
 });

где handleUncaughtException(thread, e, defaultEH); записывает в журнал и передает вызов исходному UncaughtExceptionHandler.

Итак, что случилось с использованием этого кода было следующее:

  • Деятельность А создается
  • Новый обработчик исключений по умолчанию (DEH) теперь мой обработчик журнала + старый DEH
  • Деятельность B создается
  • Новый DEH теперь мой обработчик журнала + старый DEH (обработчик журнала + оригинальный DEH)
  • Деятельность C создается
  • Новый DEH теперь мой обработчик журнала + старый DEH (обработчик журнала + обработчик журнала + оригинальный DEH)

Таким образом, это бесконечно растущая цепь, вызывающая две проблемы:

  1. Указанный пользовательский код (в моем случае запись в файл журнала) будет вызываться несколько раз, что не является желаемым действием.
  2. Ссылка на defaultEh сохраняется в куче даже после завершения действия, потому что она используется цепочкой ссылок, поэтому худшее, что может произойти, - это исключение нехватки памяти.

Поэтому я добавил еще одну вещь, чтобы, наконец, сделать эту работу без проблем:

private static boolean customExceptionHandlerAttached = false;                                                                                                                                                                                                                                                                                                                                                                      

@Override                                                                                                                                                                                                                                                                                                                                                                                                                           
protected void onCreate(@Nullable Bundle savedInstanceState) {                                                                                                                                                                                                                                                                                                                                                                      
    super.onCreate(savedInstanceState);                                                                                                                                                                                                                                                                                                                                                                                             

    if(!customExceptionHandlerAttached) {                                                                                                                                                                                                                                                                                                                                                                                            
        final Thread.UncaughtExceptionHandler defaultEH = Thread.getDefaultUncaughtExceptionHandler();                                                                                                                                                                                                                                                                                                                              
        Thread.setDefaultUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() {                                                                                                                                                                                                                                                                                                                                           
            @Override                                                                                                                                                                                                                                                                                                                                                                                                               
            public void uncaughtException(Thread thread, Throwable e) {                                                                                                                                                                                                                                                                                                                                                             
                 handleUncaughtException(thread, e, defaultEH);                                                                                                                                                                                                                                                                                                                                                                      
            }                                                                                                                                                                                                                                                                                                                                                                                                                       
        });                                                                                                                                                                                                                                                                                                                                                                                                                         
        customExceptionHandlerAttached = true;                                                                                                                                                                                                                                                                                                                                                                                      
    }                                                                                                                                                                                                                                                                                                                                                                                                                               
}

С этим решением мы можем убедиться, что:

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

Ответ 6

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

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