Android Global Exception Handler

Background / Motivation

Sometimes it is quite useful to handle/catch exceptions in a central handler. Typical samples are:

  • Handle Authorization problems e.g. with your backend
  • Central dispatching of these error to an Exception Collector like Crashlytics (ur just send an email)
  • Just show a message dialog to the user

Implementation

Just creating an Exception is straight forward java.lang.Thread.UncaughtExceptionHandler. The little more tricky part is integrating it into an Android application. Two obvious ways we might choose from:

  • Attach the Exception Handler in the Application
    • Can’t open UI Dialogs or other Activities properly
    • Will be executed for any activity
  • Attach the Exception Handler in an Activity
    • May start other activities
    • Needs a Base class to be applied in an easy way to all activities

Exception as Application Handler

Typical here is to log the exception and later on send it to the backend, e.g. after the application was restarted.

This sample code just logs each exception into a file, which we can later on inspect and send to the backend if we like.

Exception Handler

public class LoggingExceptionHandler implements Thread.UncaughtExceptionHandler {
    private final static String TAG = LoggingExceptionHandler.class.getSimpleName();
    private final static String ERROR_FILE = MyAuthException.class.getSimpleName() + ".error";

    private final Context context;
    private final Thread.UncaughtExceptionHandler rootHandler;

    public LoggingExceptionHandler(Context context) {
        this.context = context;
        // we should store the current exception handler -- to invoke it for all not handled exceptions ...
        rootHandler = Thread.getDefaultUncaughtExceptionHandler();
        // we replace the exception handler now with us -- we will properly dispatch the exceptions ...
        Thread.setDefaultUncaughtExceptionHandler(this);
    }

    @Override
    public void uncaughtException(final Thread thread, final Throwable ex) {
        try {
            Log.d(TAG, "called for " + ex.getClass());
            // assume we would write each error in one file ...
            File f = new File(context.getFilesDir(), ERROR_FILE);
            // log this exception ...
            FileUtils.writeStringToFile(f, ex.getClass().getSimpleName() + " " + System.currentTimeMillis() + "\n", true);
        } catch (Exception e) {
            Log.e(TAG, "Exception Logger failed!", e);
        }

    public static final List<String> readExceptions(Context context) {
        List<String> exceptions = new ArrayList<>();
        File f = new File(context.getFilesDir(), ERROR_FILE);
        if (f.exists()) {
            try {
                exceptions = FileUtils.readLines(f);
            } catch (IOException e) {
                Log.e(TAG, "readExceptions failed!", e);
            }
        }
        return exceptions;
    }
}

Activation of the Exception Handler

We need now only to attach it once in our Application:

public class MyApp extends Application {
    @Override
    public void onCreate() {
        super.onCreate();
        new LoggingExceptionHandler(this);
    }
}

Enable the Android Application

And of course make sure it is attached in our AndroidManifest.xml.

<application
    android:name=".MyApp"

Exception Handler in an Activity

Attaching an exception handler in the activity allows us to do a little more, most important here starting a different activity work — in the case of the ApplicationContext it would just hang.

Exception Handler

In this case, we check the exceptions if we could gracefully handle them. If so the start the appropriate activity and could pass more informations to it if needed.

public class MyExceptionHandler implements Thread.UncaughtExceptionHandler {

    public static final String EXTRA_MY_EXCEPTION_HANDLER = "EXTRA_MY_EXCEPTION_HANDLER";
    private final Activity context;
    private final Thread.UncaughtExceptionHandler rootHandler;

    public MyExceptionHandler(Activity context) {
        this.context = context;
        // we should store the current exception handler -- to invoke it for all not handled exceptions ...
        rootHandler = Thread.getDefaultUncaughtExceptionHandler();
        // we replace the exception handler now with us -- we will properly dispatch the exceptions ...
        Thread.setDefaultUncaughtExceptionHandler(this);
    }

    @Override
    public void uncaughtException(final Thread thread, final Throwable ex) {
        if (ex instanceof MyAuthException) {
            // note we can't just open in Android an dialog etc. we have to use Intents here
            // http://stackoverflow.com/questions/13416879/show-a-dialog-in-thread-setdefaultuncaughtexceptionhandler

            Intent registerActivity = new Intent(context, AuthActivity.class);
            registerActivity.putExtra(EXTRA_MY_EXCEPTION_HANDLER, MyExceptionHandler.class.getName());
            registerActivity.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
            registerActivity.addFlags(Intent.FLAG_ACTIVITY_NEW_DOCUMENT);

            context.startActivity(registerActivity);
            // make sure we die, otherwise the app will hang ...
            android.os.Process.killProcess(android.os.Process.myPid());
            System.exit(0);
        } else {
            rootHandler.uncaughtException(thread, ex);
        }
    }
}

Activation of the Exception Handler

Now it gets a little more messy. As we need to activate/init this handler with an Activity we have to ensure that either in each Activity or we provide a base activity all other inherit from.

public abstract class BaseActivity extends AppCompatActivity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        new MyExceptionHandler(BaseActivity.this);
    }
}

Sample Code on Github

Sample code on GitHub

Paul Sterl has written 55 articles

One thought on “Android Global Exception Handler

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>