How to re-throw an exception

2019-04-04 08:59发布

问题:

In my onCreate() I set an UncaughtException handler as follows:

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

It works OK, but I would like to get back the system's default behavior of displaying the force-close dialog to the user.

If I try to replace the KillProcess() call with a throw throwable the compiler complains that I need to surround it with a try/catch.

If I surround it with a 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 {               
        }
    }
});

The compiler still complains that throw throwable needs to be surrounded with a try/catch.

How do I re-throw that throwable? Such that except for that informative Log.e() the system behaves exactly as before: As is I never set a default UncaughtException handler.

回答1:

Try:

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

and then Thread.setDefaultUncaughtExceptionHandler(new CustomExceptionHandler());

Adapted from this answer.



回答2:

If you set default uncaught exception handler, you are expected to consume the exception in it. That is reflected by the fact that uncaughtException does not declare any exception.

There should be no obvious reason to re-throw it. It will just be printed in log second time and thread will die anyway. If you really want that, then just wrap throwable in RuntimeException and re-throw.



回答3:

There is no reason to rethrow the Throwable, as per the javadoc, it is simply ignored. The thread is terminating at this point, you're just setting up whatever last actions it's to attempt before exiting.

For the sake of argument, if you did want to rethrow a throwable, you'd do something like this:

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


回答4:

first, you don't need to re-throw the exception. uncaughtException() does not consume the exception. you do however have to call through to the default uncaught exception handler's method. so something like,

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

second, you don't need to kill the process yourself. the default UEH will handle that when you call through to it.

third, the default UEH will show (or cause to be shown) the standard crash (force close) dialog to the user. keep in mind that if your method hangs (because you are doing IO for example), then the user will not see the crash dialog until your method exits.