Here are some tips on how to handle and test orientation changes in Android 2
This post applies to Android 2.x, since onRetainNonConfigurationInstance() is deprecated in Android 3.x.
In my previous post I showed one method I use to test orientation changes. The standard way of handling orientation change is to save the results of expensive operations
in onRetainNonConfiguration(), and then when the activity is recreated that data can be re-used.
From the Android developer documentation
Finally, remember that onRetainNonConfigurationChange() should be used only to retain data that is expensive to load. Otherwise, keep it simple and let Android do everything.
This function is called purely as an optimization, and you must not rely on it being called
This means that onRetainNonConfigurationChange() is supposed to be an optimization, so the activity should be able to recreate the data if required
Now here is a list some things that I will usually save in onRetainNonConfigurationChange().
Expensive operation results – just like the documention says. After all you don’t want your app to be re-doing things like database queries, network calls or complex
calculations every time the user flips the phone.
AsyncTask – there are some situations where a running AsyncTask will be saved, so that it can continue it’s processing after the orientation change (rather than starting the task again). Makes sense since one of reasons to use an AsyncTask is to handle long-running operations.
Intermediate data – I was using some fields in the activity to hold some (non-expensive) data, so I didn’t bother to save it because I thought it was trivial. The result was NullPointerExceptions because that data was required either in the onCreate() or later on, e.g. onDialogCreate()when I wanted to display that data in a message. So you can either save this data, re-create it in onCreate() or at least do a null check before using it.
Maps – if the activity displays a map (e.g. using a MapActivity), then it might be more user friendly to save things like the zoom level, satellite view option, and the centre point of the map. This is so that the user has a similar map view after the orientation changes.
Some other tips not related to saving state
Dialogs– if you are doing your own dialog handling, instead of letting the activity do it by using onCreateDialog() and showDialog(), then you need to handle the situation
where the dialog is displayed when the orientation change occurs. I generally let the activity do the hard lifting, except maybe in cases where the life cycle of the dialog doesn’t
match the activity, e.g. a progress dialog for an AsyncTask.
Generally in my unit tests, I will follow each dialog display with an orientation change to check that afterwards:
1. the dialog is still displayed
2. if the dialog shows data, that the data hasn’t changed
Layouts – if you have alternate layouts for portrait and landscape, goes without saying that you need to test both! This includes things like testing the order of focus for the views, etc. since the views may be in different positions in the different layouts.
This is the reason that in my previous post: Test Android orientation changes with Robotium I ran the test methods multiple time starting in both portrait and landscape mode.
Some more testing tips
- Some versions of the emulator may have bugs that show up when your test invokes an orientation change, e.g. the 2.3 version will allow your app to change normally from portrait to landscape, but then it has problems when you try to change back to portrait again. The test will still run OK, the will not look right in the emulator window.
- If you are using the emulator and have some Robotium or instrumentation test code to click on an item in a list by index, e.g. solo.clickInList(1). Then the orientation change may cause some test failures when going into landscape mode.
This is because fewer items being displayed in the list in landscape than in portrait mode, of course this is only a problem is there are more items in the list than can be displayed in the view or ‘page’.
See if you can use solo.clickOnText() instead with the option to allow scrolling if required.
If you can think of anything else that might be useful, please let me know!