September 2, 2014

Rotational Forces, Part Two

A few weeks back, I wrote about how rotations, including sliding out the keyboard on the G1, affect your Android application. Ed Burnette chimed in with a couple of other points in a blog comment, so I wanted to expand upon what he presented there.

The original post focused on the fact that a rotation, by default, will destroy and recreate your activity, no different than if the activity were reclaimed due to low memory space or other conditions. Hence, in theory, whatever logic you wrote to handle being destroyed to release memory would also cover you for a rotation. Usually, this involves onSaveInstanceState(), so you can persist your current state and get it back in onCreate() or onRestoreInstanceState().

Today, we’ll cover a second approach — onRetainNonConfigurationInstance() — in an adapted excerpt from Version 1.4 of The Busy Coder’s Guide to Android Development.

The problem with onSaveInstanceState() is that you are limited to a Bundle. That’s because this callback is also used in cases where your whole process might be terminated (e.g., low memory), so the data to be saved has to be something that can be serialized and has no dependencies upon your running process.

For some activities, that limitation is not a problem. For others, though, it is more annoying. Take an online chat, for example. You have no means of storing a socket in a Bundle, so by default, you will have to drop your connection to the chat server and re-establish it. That not only may be a performance hit, but it might also affect the chat itself, such as you appearing in the chat logs as disconnecting and reconnecting.

One way to get past this is to use onRetainNonConfigurationInstance() instead of onSaveInstanceState() for “light” changes like a rotation. Your activity’s onRetainNonConfigurationInstance() callback can return an Object, which you can retrieve later via getLastNonConfigurationInstance(). The Object can be just about anything you want – typically, it will be some kind of “context” object holding activity state, such as running threads, open sockets, and the like. Your activity’s onCreate() can call getLastNonConfigurationInstance() – if you get a non-null response, you now have your sockets and threads and whatnot. The biggest limitation is that you do not want to put in the saved context anything that might reference a resource that will get swapped out, such as a Drawable loaded from a resource.

Let’s look at an example. Below is a layout for a simple UI with two buttons:

[sourcecode language='xml']

android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
>