Save/restore instance state

From Android Wiki

Revision as of 08:48, 31 January 2013 by Ldo (Talk | contribs)
Jump to: navigation, searcha

Consider what happens when the user rotates the orientation of the phone, when your activity is frontmost: unless you took special action to handle this situation, the default behaviour of the system is to destroy your activity and relaunch it in the new orientation. But before it is destroyed, it is asked to save its instance state, so that this can be passed to the relaunched activity for restoration. This way, the illusion is presented to the user that your activity simply changed its orientation, without any break in the interaction.

A similar thing happens if your activity was left running but is not frontmost, and the system is getting low on resources and needs to free some up, so it decides to ask you to save your instance state, and then destroy you. When later, the user presses the Back key sufficient times to return to your activity, the system will automatically relaunch you and pass you your saved instance state for restoration, so the user never knows that you ever stopped running in the meantime.

Saving your instance state is not done when the user presses the Back key with your activity frontmost: the convention is that the Back key terminates the activity: it indicates that the user has finished with the activity and doesn’t need it running any more (for now).

Note that it is up to you whether you in fact treat save/restore instance versus terminate differently: your app might save all its state in persistent storage on quitting, in which case you don’t need to do anything special for save/restore instance state. Or you might omit things like positions in scrolling lists from the former, and only save them in the latter.

Save/restore instance state happens at the activity level, and at the widget level.

Save/Restore Activity Instance State

At the activity level, your onCreate, onSaveInstanceState and onRestoreInstanceState methods all get passed a Bundle object into which you can put, and from which you can retrieve, any information you like. The state you previously saved in onSaveInstanceState is available for restoration in both the onCreate and onRestoreInstanceState methods, to save you doing needless initialization in the former which is only going to be overwritten in the latter.

You can use this to save UI state information which is not part of the state of any visible widget; there is no need to do it for visible widgets (at least the standard ones), since widgets have their own mechanisms for saving/restoring state (see below). You can also do this for your own widgets if you do not implement saving/restoring instance state in those widgets.

Save/Restore Widget Instance State

The standard Android widgets take care of saving/restoring their own state. But if you implement your own custom widgets, you will need to manage this for yourself. Unlike at the Activity level, there is no predefined Bundle object that is passed to you: instead, you have to define your own subclass of Parcelable to contain whatever state fields you need, and return one of these when your onSaveInstanceState method is called. This object will be passed to your onRestoreInstanceState method to restore your state.

Your Parcelable subclass in turn has to be able to save its state fields into a Parcel. Restoring these state fields from a Parcel is done in a slightly odd way, due to Java language limitations: your Parcelable subclass must define a public static field called CREATOR, the contents of which are an instance of a custom subclass of Parcelable.Creator, which knows how to (re)create an instance of your custom Parcelable subclass from a Parcel.

Personally I find Parcels to be a bit error-prone to use directly, since items must be read back from them in exactly the same order they were written. I prefer to use a Bundle, since this allows you to associate data items with your own keywords. Then the Parcel only needs to hold this single Bundle for you. For the details of how to use Bundles in Parcels, see Parcels and Bundles.

Your Parcelable subclass also needs to hold the Parcelable returned from and passed to the onSaveInstanceState and onRestoreInstanceState methods of the widget superclass. If you subclass from View, then it’s worth noting that the Parcelable generated by that is an AbsSavedState, which holds no state at all (it is in fact the AbsSavedState.EMPTY_STATE value), but View.onRestoreInstanceState expects you to pass it back nonetheless.

Sample Code

  • View Cache Demo includes a custom DrawView widget that implements saving and restoration of instance state.
  • Memory Hog is a utility to grab so much RAM that it forces background apps to be killed, to test that they correctly handle saving and restoring their instance state.
Personal tools