Developing robust Android applications is challenging. At any moment your application can be interrupted, sent the background or just simply terminated. There are a few hooks to help you prepare for these scenarios but it’s such a dynamic environment it can be hard to anticipate how your application will behave.
Take the activity lifecycle for example. Under normal circumstances activities are only destroyed when their finish() method is called or the system needs to free up some memory. From a testing perspective this isn’t very deterministic so testing what happens when activities are destroyed is either forgotten about or not given the attention it deserves.
Luckily there are tools to help in these scenarios. The Dev Tools App is particularly useful. It’s automatically installed with every virtual device created using the Android Virtual Device Manager in Eclipse.
Testing Activity Destruction
To test what happens to your app when activities are destroyed tick the Immediately destroy activities checkbox under Development Settings in Dev Tools. This instructs Android to immediately destroy activities that are no longer visible. Under normal conditions you might never get to this test scenario if you don’t explicitly call finish() on your activities. It’s amazing the subtle bugs this can throw up.
Testing Process Termination
Another very useful test is to see what happens when your application’s process is terminated. When I stated out with UPM I received quite a number of crash reports that initially baffled me. The stack traces suggested situations that I just couldn’t recreate. It wasn’t until I started thinking about the impact of process termination that I found the root of the problems.
When a terminated application is restarted Android will try and return the user to whatever activity was previously in the foreground. This can cause problems if the activity assumes too much about the application’s state, e.g. what static variables are initialized. Restarting the application means there’s a new process so the static state of the previous instance is gone. Here’s how I test this scenario.
First I start the application in an emulator as normal. Once I’ve made it to the activity under test I hit the Home button to send the application into the background. Now I need to kill the application’s process. There’s a few ways to do this. My favourite is to use adb. adb is located in the Android SDK platform-tools directory. Running
$ adb shell
starts a shell on the emulator. From there I use
to find the application’s process and
$ kill -9 <pid>
to kill the process. Once I’ve killed the process I go back to the emulator and hit the application’s icon to restart it. Android will try to resume the activity that was previously in the foreground. Ideally there should be no problems but if there are they’ll usually present themselves as a NullPointerException with a “Force Close” dialog for the user.
Android can be a difficult, confusing platform to work with. This is particularly true if you’re coming from a regular desktop application environment. There’s a paradigm shift in thinking required to fully appreciate the transient nature of the Android environment. Thankfully, once you’ve made that leap things do get easier. The most useful resources I’ve found are the Android Developer’s Guide and Stackoverflow.