This lecture explains the basic concepts behind Android crash handling and different approaches to it. I decided to make a simple list of notes so every person can use this list whenever he decides to implement a solution from the video without having to watch the video again.
What people do mostly when the app crashes?
- Uninstall the app
- Stop using it
- Check for app updated
- Look for alternative
Types of crashes
- Java crashes
- Native crashes
The lecture focuses on the first type.
Threads & Exceptions
When an exception occurs it bubbles up to the
run() method of the Thread and then it is delegated to the Threads exception handler. Every thread can have an Exception handler.
Android main() & Default exception handler
As any java program, Android also has a
main(String argv) method which is where the app starts. There a default exception handler is set. This first thing the UncaughtHandler does is logging the crash to Logcat. Then it displays the System error dialog and then it kills the process by any means.
The crash dialog has only two options: Report and OK. Because Google is very concerned with the privacy of the users, that’s why they want your confirmation that you want the error reported, because the report may contain some personal information.
Handling exceptions yourself
You can register an exception handler in your Application class, send the exception to the cloud and then delegate it to the default handler which will crash and display the crash dialog to the user. You don’t need to send the error to your custom error server, you can use Crashlytics, Bugsnag etc.
Android exceptions can be tricky to reproduce because of the callback approach that is used inside of it. So a callback may be executed later in the lifecycle of a component and you may not know what the exact problem is. That’s why reproducing is the answer.
- Ask the customer to tell you how the crash happened
- Contact the user in Google Play store reviews
- Use custom dialogs when a crash occurs. Allow them to express what happened in the dialog.
Crash activity lifecycle listener
Use it to start the latest activity that was previously displayed when an exception occurs.
You can collect information about the device like:
- Is it a tablet
- OS version, orientation
- jailbroken, Locale, manufacturer, model
- SHA version of the code to compare it with the latest build
A list of the view hierarchy like:
Capturing screenshots is not a good idea as they may contain sensitive information.
Taken from Espressos RootsOracle class which uses reflection to get access to all windows of the process.
Flight box – recording all the important information what happened before crash
Have a high level history log about network requests, displayed screens, click actions etc.
Memory leak detection
How to prevent crashes
Exception = something unexpected happened
Instead of using defensive programming, just let the exception bubble. Make the app crash faster so you can fix the problem faster. Throwing exceptions when a field is empty will give you the insight when the exception happened before it was actually hidden in the callbacks of Android. Do offensive programming!
Making customers happy
- Integration tests with Espresso
- Smoke testing – try to break an app at a party with other devs
- Dogfood/Beta – go join the customers to see how they use your app
- Staged rollout – release a version to a part of your users
- Crash Rate – not user crashes per day, the real question is if you want to do a key action in the app, what is the chance that you will get an exception