Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Rethrow UncaughtExceptionHandler Exception after Logging It

In my Application class I am trying to catch a force close before it happens, so I can log it and then rethrow it so the android can handle it. I do this since some users do not report force closes.

I am developing in eclipse, and eclipse is not allowing me to rethrow the exception. It shows an error saying "Unhandled exception type Throwable: Surround with try/catch". How can I rethrow the exception?

public class MainApplication extends Application
{
    @Override
    public void onCreate()
    {
    super.onCreate();

    try
    {
        //Log exception before app force closes
        Thread.currentThread().setUncaughtExceptionHandler(new UncaughtExceptionHandler() {
            @Override
            public void uncaughtException(Thread thread, Throwable ex) {
                AnalyticsUtils.getInstance(MainApplication.this).trackEvent(
                        "Errors",                       // Category
                        "MainActivity",                 // Action
                        "Force Close: "+ex.toString(),  // Label
                        0);                             // Value
                AnalyticsUtils.getInstance(MainApplication.this).dispatch();

                Toast.makeText(MainApplication.this, "Snap! Something broke. Please report the Force Close so I can fix it.", Toast.LENGTH_LONG);

                //rethrow the Exception so user can report it
                //throw ex; //<-- **eclipse is showing an error to surround with try/catch**
            }
        });

    } catch (Exception e)
    {
        e.printStackTrace();
    }
}

}

like image 769
Ryan R Avatar asked Jan 29 '12 04:01

Ryan R


People also ask

When should you Rethrow an exception?

If a catch block cannot handle the particular exception it has caught, you can rethrow the exception. The rethrow expression ( throw without assignment_expression) causes the originally thrown object to be rethrown.

Why do we Rethrow an exception C#?

In C# 5.0, a mechanism was added that enables the throwing of a previously thrown exception without losing the stack trace information in the original exception. This lets you rethrow exceptions, for example, even from outside a catch block and, therefore, without using an empty throw.

How do you Rethrow in C#?

An exception caught by one catch can be rethrown so that it can be caught by an outer catch. To rethrow an exception, you simply specify throw, without specifying an expression.

How do you throw uncaught exception?

Throwing an exception is as simple as using the "throw" statement. You then specify the Exception object you wish to throw. Every Exception includes a message which is a human-readable error description. It can often be related to problems with user input, server, backend, etc.


2 Answers

Apologies, not an Android expert - but looks like you can't throw ex because your method signature "void uncaughtException(Thread, Throwable)" doesn't declare that it "throws" anything.

Assuming you're overriding an API interface and (a) can't modify this signature and (b) don't want to because you'd be throwing it out of context, could you instead use a decorator pattern and basically subclass the default UncaughtExceptionHandler implementation to log your message and then let it carry on processing as usual?

Edit: untested, but this might look a bit like:

    final UncaughtExceptionHandler subclass = Thread.currentThread().getUncaughtExceptionHandler();
    Thread.currentThread().setUncaughtExceptionHandler(new UncaughtExceptionHandler() {
        @Override
        public void uncaughtException(Thread thread, Throwable ex) {
            // your code 
            AnalyticsUtils.getInstance(MainApplication.this).trackEvent(
                    "Errors",                       // Category
                    "MainActivity",                 // Action
                    "Force Close: "+ex.toString(),  // Label
                    0);                             // Value
            AnalyticsUtils.getInstance(MainApplication.this).dispatch();
            Toast.makeText(MainApplication.this, "Snap! Something broke. Please report the Force Close so I can fix it.", Toast.LENGTH_LONG).show();

            // carry on with prior flow
            subclass.uncaughtException(thread, ex);
        }
    });
like image 196
Capn Sparrow Avatar answered Oct 05 '22 07:10

Capn Sparrow


For anyone finding this question only now, I'm not sure if any of the above answers were correct when posted, but they're not now. What you want nowadays is to create a new class that implements Thread.UncaughtExceptionHandler and in the constructor, save Thread.getCurrentUncaughtExceptionHandler() to a field, and you call its uncaughtException(Thread, Throwable) at the end of your uncaughtException(Thread, Throwable) method. Then you call Thread.setUncaughtExceptionHandler() from whatever code instantiates your class, often MainApplication.onCreate.

So the full code would look something like:

//MainApplication.java
public class MainApplication extends Application {
    @Override
    public void onCreate() {
        super.onCreate();
        CustomUncaughtExceptionHandler cueh = new CustomUncaughtExceptionHandler();
        Thread.setDefaultUncaughtExceptionHandler(cueh);
    }
}

//CustomUncaughtExceptionHandler.java
class CustomUncaughtExceptionHandler implements Thread.UncaughtExceptionHandler {
    private Thread.UncaughtExceptionHandler oldHandler;

    CustomUncaughtExceptionHandler() {
        oldHandler = Thread.getDefaultUncaughtExceptionHandler();
    }

    @Override
    public void uncaughtException(Thread thread, Throwable ex) {
        AnalyticsUtils.getInstance(MainApplication.this).trackEvent(
                "Errors",                       // Category
                "MainActivity",                 // Action
                "Force Close: "+ex.toString(),  // Label
                0);                             // Value
        AnalyticsUtils.getInstance(MainApplication.this).dispatch();
        if (oldHandler != null) {
            oldHandler.uncaughtException(thread, ex);
        else {
            System.exit(1);
        }
    }
}

You can also store the original default uncaught exception handler somewhere else for restoration later (or add a getOldHandler() method) if for whatever reason you decide you don't want your code to run anymore.

like image 1
icodestuff Avatar answered Oct 05 '22 07:10

icodestuff