Saving Data Across Rotation
Android does a great job of providing alternative resources at the right time.However, destroying and recreating activities on rotation can cause headaches, too, like GeoQuiz's bug of reverting back to the first question when the device is rotated.
To fix this bug, the post-rotation QuizActivity needs to know the old value of mCurrentIndex.You need a way to save this data across a runtime configuration change, like rotation.One way to do this is to override the Activity method
protected void onSaveInstanceState(Bundle outState)
This method is normally called by the system before onPause(), onStop(), and onDestroy().
The default implementation of onSaveInstanceState(...) asks all of the activity's views to save their state as data in the Bundle object. A Bundle is a structure that maps string keys to values of certain limited types.
You have seen this Bundle before. It is passed into onCreate(Bundle)
@Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); ...
When you override onCreate(...), you call onCreate(...) on the activity's superclass and pass in the bundle you just received.In the superclass implementation, the saved state of the views is retrieved and used to recreate the activity's view hierarchy.
Overriding onSaveInstanceState(Bundle)
You can override onSaveInstanceState(...) to save additional data to the bundle and then read that data back in onCreate(...).This is how you are going to save the value of mCurrentIndex across rotation.
First, in QuizActivity.java, add a constant that will be the key for the key-value pair that will be stored in the bundle.
Listing 3.5 Adding a key for the value (QuizActivity.java)
public class QuizActivity extends Activity { private static final String TAG = "QuizActivity"; private static final String KEY_INDEX = "index"; Button mTrueButton; ...
Next, override onSaveInstanceState(...) to write the value of mCurrentIndex to the bundle with the constant as its key.
Listing 3.6 Overriding onSaveInstanceState(...) (QuizActivity.java)
mNextButton.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { mCurrentIndex = (mCurrentIndex + 1) % mAnswerKey.length; updateQuestion(); } }); updateQuestion(); } @Override public void onSaveInstanceState(Bundle savedInstanceState) { super.onSaveInstanceState(savedInstanceState); Log.i(TAG, "onSaveInstanceState"); savedInstanceState.putInt(KEY_INDEX, mCurrentIndex); }
Finally, in onCreate(...), check for this value. If it exists, assign it to mCurrentIndex.
Listing 3.7 Checking bundle in onCreate(...) (QuizActivity.java)
... if (savedInstanceState != null) { mCurrentIndex = savedInstanceState.getInt(KEY_INDEX, 0); } updateQuestion(); }
Run GeoQuiz and press Next.No matter how many device or user rotations you perform, the newly-minted QuizActivity will “remember” what question you were on.
Note that the types that you can save to and restore from a Bundle are primitive types and objects that implement the Serializable interface. When you are creating custom classes, be sure to implement Serializable if you want to save them in onSaveInstanceState(...).
Testing the implementation of onSaveInstanceState(...) is a good idea - especially if you are saving and restoring objects.Rotation is easy to test; testing low-memory situations is harder.There is information at the end of this chapter about how to simulate your activity being destroyed by Android to reclaim memory.