: Beginning Android

Now With More Savings!

Now With More Savings!

The problem with onSaveInstanceState() is that you are limited to a Bundle. Thats 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 activitys 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 activitys 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.

Lets take a look at the Rotation/RotationTwo sample project, which uses this approach to handling rotations. The layouts, and hence the visual appearance, is the same as with Rotation/RotationOne. Where things differ slightly is in the Java code:

publicclass RotationTwoDemoextends Activity {
staticfinal int PICK_REQUEST = 1337;
Button viewButton =null;
Uri contact =null;
@Override
public voidonCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
Button btn = (Button)findViewById(R.id.pick);
btn.setOnClickListener(new View.OnClickListener() {
public voidonClick(View view) {
Intent i =new Intent(Intent.ACTION_PICK,
Uri.parse("content://contacts/people"));
startActivityForResult(i, PICK_REQUEST);
}
});
viewButton = (Button)findViewById(R.id.view);
viewButton.setOnClickListener(new View.OnClickListener() {
public voidonClick(View view) {
startActivity(newIntent(Intent.ACTION_VIEW, contact));
}
});
restoreMe();
viewButton.setEnabled(contact!=null);
}
@Override
protected voidonActivityResult(int requestCode, int resultCode,
Intent data) {
if (requestCode==PICK_REQUEST) {
if (resultCode==RESULT_OK) {
contact = data.getData();
viewButton.setEnabled(true);
}
}
}
@Override
public ObjectonRetainNonConfigurationInstance() {
return(contact);
}
private voidrestoreMe() {
contact =null;
if (getLastNonConfigurationInstance()!=null) {
contact = (Uri)getLastNonConfigurationInstance();
}
}
}

In this case, we override onRetainNonConfigurationInstance(), returning the actual Uri for our contact, rather than a string representation of it. In turn, restoreMe() calls getLastNonConfigurationInstance(), and if it is not null, we hold onto it as our contact and enable the View button.

The advantage here is that we are passing around the Uri rather than a string representation. In this case, that is not a big saving. But our state could be much more complicated, including threads and sockets and other things we cannot pack into a Bundle.


: 1.232. /Cache: 3 / 1