Как повторно выбросить исключение

В моем onCreate () я установил обработчик UncaughtException следующим образом:

Thread.setDefaultUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() {
    @Override
    public void uncaughtException(Thread thread, Throwable throwable) {
       Log.e(getMethodName(2), "uncaughtException", throwable);
       android.os.Process.killProcess(android.os.Process.myPid());
    }
});

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

Если я попытаюсь заменить вызов KillProcess() на throw throwable, компилятор пожалуется, что мне нужно окружить его командой try / catch.

Если я окружу это попыткой / уловкой:

Thread.setDefaultUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() {
    @Override
    public void uncaughtException(Thread thread, Throwable throwable) {
        try {
            Log.e(getMethodName(2), "uncaughtException", throwable);
            throw throwable;
        }
        catch (Exception e) {           
        }
        finally {               
        }
    }
});

Компилятор по-прежнему жалуется, что throw throwable нужно окружить попыткой / уловом.

Как мне перебросить этот метательный предмет? Таким образом, за исключением этого информативного Log.e() система ведет себя точно так же, как и раньше: как и прежде, я никогда не устанавливал обработчик UncaughtException по умолчанию.


person Eternal Learner    schedule 27.06.2012    source источник


Ответы (4)


Пытаться:

public class CustomExceptionHandler implements UncaughtExceptionHandler {

    private UncaughtExceptionHandler defaultUEH;

    public CustomExceptionHandler() {
        this.defaultUEH = Thread.getDefaultUncaughtExceptionHandler();
    }

    public void uncaughtException(Thread t, Throwable e) {
        Log.e("Tag", "uncaughtException", throwable);
        defaultUEH.uncaughtException(t, e);
    }
}

а затем Thread.setDefaultUncaughtExceptionHandler(new CustomExceptionHandler());

Адаптировано из этого ответа.

person Jeshurun    schedule 27.06.2012
comment
Извините, но это приводит к бесконечному потоку неперехваченных исключений и отсутствию диалогового окна принудительного закрытия. Не то, что я ищу. - person Eternal Learner; 28.06.2012

Если вы установите обработчик неперехваченных исключений по умолчанию, ожидается, что исключение будет использовано в нем. Это отражено в том факте, что uncaughtException не объявляет никаких исключений.

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

person Alex Gitelman    schedule 27.06.2012
comment
Я понимаю и согласен с тем, что не должно быть очевидных причин для его повторного закидывания. Единственная причина, по которой я определяю этот обработчик UncaughtException по умолчанию, заключается в том, что нет журнала в первый раз!. Поэтому, если система не печатает трассировку стека, я хочу ее распечатать. Отсюда и обработчик. Я был очень доволен поведением системы по умолчанию, за исключением ее необъяснимой неспособности распечатать трассировку стека этого неперехваченного исключения из android.net.http.HttpsConnection.openConnection(). +1. - person Eternal Learner; 28.06.2012

Нет причин для повторного выброса Throwable согласно javadoc, он просто игнорируется. На этом этапе поток завершается, вы просто настраиваете любые последние действия, которые он пытается выполнить перед выход.

Ради аргумента, если вы действительно хотите повторно выбросить throwable, вы бы сделали что-то вроде этого:

public void reThrow(Throwable t) {
    if (RuntimeException.class.isAssignableFrom(t.getClass())) {
        throw (RuntimeException)t;
    } else if (Error.class.isAssignableFrom(t.getClass())) {
        throw (Error) t;
    } else {
        throw new UndeclaredThrowableException(t);
    }
}
person Affe    schedule 27.06.2012
comment
+1. Я даже не буду пытаться перебрасывать, потому что согласен с вашим утверждением (см. мой комментарий к @AlexGitelman). Тем не менее, было бы неплохо показать пользователю знакомый диалог принудительного закрытия. Есть идеи, как это сделать? - person Eternal Learner; 28.06.2012

Во-первых, вам не нужно повторно генерировать исключение. uncaughtException() не использует исключение. однако вам необходимо вызвать метод обработчика неперехваченных исключений по умолчанию. так что-то вроде,

class MyUEH implements UncaughtExceptionHandler {
  private static final UncaughtExceptionHandler default = Thread.getDefaultUncaughtExceptionHandler();

    public void uncaughtException(Thread t, Throwable e) {
        Log.e("Tag", "uncaughtException", throwable);
        default.uncaughtException(t, e);
    }
}

во-вторых, вам не нужно убивать процесс самостоятельно. UEH по умолчанию обработает это, когда вы позвоните ему.

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

person Jeffrey Blattman    schedule 27.06.2012
comment
Мне нравится ваш ответ, но реальность такова, что если я закомментирую оператор killProcess() в первой версии своего обработчика (оставив там только оператор Log.e(), диалоговое окно принудительного закрытия не отображается, и представление приложения просто зависает, пока я не закрою вручную приложение. - person Eternal Learner; 28.06.2012
comment
Да, ты прав. я забываю лакомый кусочек о вызове UEH по умолчанию. - person Jeffrey Blattman; 28.06.2012