In all applications, there are those exceptions, those bugs that no one expected. Try as we might to think of every conceivable error, exception, or issue, we developers miss some things. When this happens on a device “out in the wild” – meaning on a device in the hands of the mobile users – we often don’t know it happened, let alone be able to better deal with the problem in the future.
Catching the Unexpected – using the UncaughtExceptionHandler
The first task in wrestling with this issue is to capture the unexpected. How are you expected to capture the unexpected exception? By definition, this almost sounds like an oxymoron.
In Android, the answer is to create an UncaughtExceptionHandler. An UncaughtExceptionHandler is an interface defined on the Thread class in the Android SDK. Create an instance of UncaughtExceptionHandler on an object that you want to handle any uncaught Throwable of a thread. Uncaught Throwables are defined as those that are not dealt with (for example by try/catch) and would end up terminating the thread.
By way of example, first let me create a small piece of code that creates an uncaught exception. In this admittedly contrived and improbable example, the doIt( ) method is set up as an onClick handler for a button push on an activity. In the doIt( ) method, an array is accessed beyond its bounds causing a java.lang.ArrayIndexOutOfBoundsException to be thrown and killing the main thread and the application.
Below, is an example code of an UncaughtExceptionHandler defined in a custom Application class. This will catch any uncaught exception that happens on the main/”UI” thread – in this case handling the ArrayIndexOutOfBoundsException caused by the TestActivity. Notice that the UncaughtExceptionHandler is set as the “default” uncaught exception handler in the onCreate( ) method of the Application instance.
The question you have to ask is once you have captured the unexpected, what do you do with it? At the point the uncaughtException( ) method of the UncaughtExceptionHandler is called, the thread is dying. There are some suggestions about how to “restart” your application. You can find one such example here in Stack Overflow. You can also just kill the DVM process and avoid the Force Close Error. You’ll find an example of that here. However, I prefer to log the issue and “phone home” to your log collection agency (see below) to report the issue. Then I allow Android’s original default UncaughtExceptionHandler to message the user (popping up the standard alert dialog), and take care of the VM clean up.
Collecting the Unexpected
If you just log the exceptions (using android.util.Log), you are no better off than you were before not logging the issue since the logs are on the device and not sent to you.
Android Crash Reports.
As of Android 2.2, a crash report system is built into Android. It allows users to optionally “report” crashes to the developer. See this Android Developers Blog post about this feature. Unfortunately, this reporting is optional on the part of the user. They can just choose to force close the application and opt not to report the issue.
Further, data is communicated through Google Feedback which may not work for you and your apps if you are not planning on working through Google Play and the Android/Google infrastructure (say perhaps you deploy your application to company devices only and those only use the company intranet ). Finally, this reporting mechanism works to protect the individual user’s privacy. All well and good, but for some issues you need to know the exact device and maybe even the user (think corporate applications versus public apps). For these reasons and others, you may need to explore the other options I have provided below.
Commercial Collection Options
Thankfully, there are many options at your disposal for collecting your unexpected exceptions (and other crash data). For those with some support budgets, there are a number of commercial packages. In most cases, you simply add the package’s JAR file(s) to your app and use their API to log. Most of these report issues to a centralized server. Cost is relatively small per device when you have many users. The table below provides an outline of some of these packages.
|Name||URL||Unofficial Price ( best that I could determine from their site)|
|Crittercism||www.crittercism.com/||$24 per monthper 100K Monthly Active Users|
|BugsNag||bugsnag.com/||$29/month including 25,000 exceptions|
|Apphance||www.apphance.com/||$99 per month for 2 apps and 50000 users|
|Bugsense||www.bugsense.com/||$99 per month for unlimited apps and 100K errors|
|Zubhium||www.zubhium.com/||$60 per month for unlimited apps for 50K error reports|
|Flurry Crash Analytics||Flurry.com||In Beta|
For those on a tighter budget (or no budget), you can roll your own solution, but you may also want to consider some open source alternatives in the list below. Some of these will require more work/customization on your part.
|Application Crash Report for Android (ACRA)||acra.ch/|
|Android Remote Stacktrace||code.google.com/p/android-remote-stacktrace|
|Android Log Collector||code.google.com/p/android-log-collector/|
This is not a complete list and I invite those with experience with other packages/tools to please provide a comment to this post to mention your experiences (good or bad) as well. Importantly, as I hope you can tell, you have lots of options.
Hopefully, you have a better plan on how to address those unwanted and unexpected exceptions in your application, and you feel armed with a set of options for how to collect your crash reports. If you or someone on your team needs help learning the Android SDK and APIs, consider taking either our introductory or advanced Android classes. We offer training in our classroom, on site or on line. Contact Intertech Training at 651-288-7100 or click here to enroll. I look forward to seeing you in class.