Saving Data Across Rotation

Android does a great job of providing alternative resources at the right time. However, destroying and re-creating activities on rotation can cause headaches, such as GeoQuiz’s bug of reverting back to the first question when the device is rotated.

To fix this bug, the post-rotation QuizActivity instance 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 called before onStop(), except when the user presses the Back button. (Remember, pressing Back tells Android the user is done with the activity, so Android wipes the activity from memory completely and does not make any attempt to save data to re-create it.)

The default implementation of onSaveInstanceState(Bundle) directs 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(Bundle), you call onCreate(Bundle) 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 re-create the activity’s view hierarchy.

Overriding onSaveInstanceState(Bundle)

You can override onSaveInstanceState(Bundle) to save additional data to the bundle and then read that data back in onCreate(Bundle). 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 AppCompatActivity {

    private static final String TAG = "QuizActivity";
    private static final String KEY_INDEX = "index";

    private Button mTrueButton;

Next, override onSaveInstanceState(Bundle) to write the value of mCurrentIndex to the bundle with the constant as its key.

Listing 3.6  Overriding onSaveInstanceState(…) (QuizActivity.java)

public class QuizActivity extends AppCompatActivity {
    ...
    @Override
    protected void onPause() {
        ...
    }

    @Override
    public void onSaveInstanceState(Bundle savedInstanceState) {
        super.onSaveInstanceState(savedInstanceState);
        Log.i(TAG, "onSaveInstanceState");
        savedInstanceState.putInt(KEY_INDEX, mCurrentIndex);
    }

    @Override
    protected void onStop() {
        ...
    }
    ...
}

Finally, in onCreate(Bundle), check for this value. If it exists, assign it to mCurrentIndex.

Listing 3.7  Checking bundle in onCreate(Bundle) (QuizActivity.java)

public class QuizActivity extends AppCompatActivity {
    ...
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        Log.d(TAG, "onCreate(Bundle) called");
        setContentView(R.layout.activity_quiz);

        if (savedInstanceState != null) {
            mCurrentIndex = savedInstanceState.getInt(KEY_INDEX, 0);
        }
        ...
    }
    ...
}

Run GeoQuiz and press NEXT. No matter how many device 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 classes that implement the Serializable or Parcelable interfaces. It is usually a bad practice to put objects of custom types into a Bundle, however, because the data might be stale when you get it back out. It is a better choice to use some other kind of storage for the data and put a primitive identifier into the Bundle instead.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.144.143.31