Catching Application Crashes with Android

I’ve recently been working on a Weather app. There have been occasions when the app has crashed. It hasn’t been a big problem in general, but problems are always big unless you know what the problem actually is. How do you trap all the exceptions?

The answer is to use an Uncaught Exception Handler. Basically, you write a new class that conforms to the UncaughtExceptionHandler interface, like this:

package com.shellmonger.weatherapp;

import java.io.PrintWriter;
import java.io.StringWriter;
import java.io.Writer;
import java.lang.Thread.UncaughtExceptionHandler;

import android.app.Activity;
import android.util.Log;

public class CustomExceptionHandler implements UncaughtExceptionHandler {
    private UncaughtExceptionHandler defaultHandler;
    private Activity activity;

    public CustomExceptionHandler(Activity activity) {
        this.defaultHandler = Thread.getDefaultUncaughtExceptionHandler();
        this.activity = activity;
    }

    public void uncaughtException(Thread t, Throwable e) {
        final Writer stringWriter = new StringWriter();
        final PrintWriter printWriter = new PrintWriter(stringWriter);
        e.printStackTrace(printWriter);
        String stacktrace = stringWriter.toString();
        printWriter.close();

        Log.e("CRASH", stacktrace);
        Log.e("CRASH", e.toString());

        // Chain to the normal uncaught exception handler
        defaultHandler.uncaughtException(t, e);
    }
}

The important code is in the uncaughtException() method. In my case, I log the stack trace to the logcat. Once that is done, call the default uncaught exception handler so that the application still crashes.

The important thing here is that you can set a breakpoint on the uncaughtException() method here. When a crash happens, the breakpoint will be hit. At least, it will be once I install the handler. To do this, add the following code to the first Activity that your app calls. Mine is called MainActivity and here is the code:

    if(!(Thread.getDefaultUncaughtExceptionHandler() instanceof CustomExceptionHandler)) {
        Thread.setDefaultUncaughtExceptionHandler(new CustomExceptionHandler(this));
    }

This should be placed after the super() call, but before any of your custom code.

This is excellent practice for debugging and during development. When you are getting ready to release your app, you need to do something else. You could, of course, implement your own crash handler that saves the stack trace off to a cloud service, then an analytics package that takes the cloud service data and does something with it – opens a GitHub issue, for example. However, that’s a lot of work. When the app is released, the symbols don’t get transmitted, which makes reading a stack trace difficult. Symbolication (the act of combining the symbols with the stack trace) is complex and required the complete symbol table for your app. In addition, if one app crashes, then a lot of apps will crash. This means that you will want to de-dupe the crashes, which means doing some sort of crash analysis to de-duplicate the crashes.

Best to leave this functionality to a service. There are, fortunately, many to choose from. If you want to “roll your own”, then check out ACRA (Application Crash Reports for Android) which is available on GitHub. If you want the security that someone is doing things for you, then check out BugSnag, which is free for individual developers.

In general, these services provide a library that provides an uncaught exception handler. It then does something to transmit the exception to their service, where it is combined with the symbols, deduped and you can look at the crashes on some sort of web interface. Ideally, new crashes allow you to create a GitHub or JIRA ticket as well. I would recommend that you utilize a crash reporting tool in the cloud for all your mobile app releases.

One thought

  1. Pingback: Dew Drop - June 13, 2017 (#2499) - Morning Dew

Comments are closed.