Search code examples
javaandroidandroid-orientationonrestoreinstancestate

Android onRestoreInstanceState not updating fully on orientation change


I have a problem in a counting program that shows how many times a method such as onCreate, onStart etc. was called and it seems to be working fine when I go from Activity1 to Activity2 and then back to Activity1 but when I switch orientation, only mResume gets increased. So for example when I start the app and switch orientation 3 times the result looks like this:

onCreate() calls:1  
onStart() calls:1  
onResume() calls:4  
onRestart() calls:1

Another wierd thing is that when I commented out mResume,mRestart and mStart from onRestoreInstanceState, then suddenly 2 variables get updated mStart and mResume.

public void onRestoreInstanceState(Bundle savedInstanceState) {
    // Always call the superclass so it can restore the view hierarchy
    super.onRestoreInstanceState(savedInstanceState);

    Log.i(TAG, "Entered the onRestoreInstanceState() method");

    // Restore state members from saved instance
    //mResume = savedInstanceState.getInt(RESUME_KEY);
    //mRestart = savedInstanceState.getInt(RESTART_KEY);
    //mStart = savedInstanceState.getInt(START_KEY);
    mCreate = savedInstanceState.getInt(CREATE_KEY);

here is the full code

public class ActivityOne extends Activity {    
    // Use these as keys when you're saving state between reconfigurations
    private static final String RESTART_KEY = "restart";
    private static final String RESUME_KEY = "resume";
    private static final String START_KEY = "start";
    private static final String CREATE_KEY = "create";

    // String for LogCat documentation
    private final static String TAG = "Lab-ActivityOne";

    // Lifecycle counters

    // TODO:
    // Create variables named
    // mCreate, mRestart, mStart and mResume
    // to count calls to onCreate(), onRestart(), onStart() and
    // onResume(). These variables should not be defined as static.

    // You will need to increment these variables' values when their
    // corresponding lifecycle methods get called.
    int mCreate;
    int mRestart;
    int mStart;
    int mResume;

    // TODO: Create variables for each of the TextViews
    // named mTvCreate, mTvRestart, mTvStart, mTvResume.
    // for displaying the current count of each counter variable

    TextView mTvCreate;
    TextView mTvRestart;
    TextView mTvResume;
    TextView mTvStart;


    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_one);

        // TODO: Assign the appropriate TextViews to the TextView variables
        // Hint: Access the TextView by calling Activity's findViewById()
        // textView1 = (TextView) findViewById(R.id.textView1);
        mTvCreate = (TextView) findViewById(R.id.create);
        mTvRestart = (TextView) findViewById(R.id.restart);
        mTvStart = (TextView) findViewById(R.id.start);
        mTvResume = (TextView) findViewById(R.id.resume);

        Button launchActivityTwoButton = (Button) findViewById(R.id.bLaunchActivityTwo);
        launchActivityTwoButton.setOnClickListener(new OnClickListener() {

            @Override
            public void onClick(View v) {
                // TODO:
                // Launch Activity Two
                // Hint: use Context's startActivity() method

                // Create an intent stating which Activity you would like to
                // start
                Intent intent = new Intent(v.getContext(), ActivityTwo.class);

                // Launch the Activity using the intent
                startActivity(intent);

            }
        });

        // Has previous state been saved?
        if (savedInstanceState != null) {

            // TODO:
            // Restore value of counters from saved state
            // Only need 4 lines of code, one for every count variable
            mCreate = savedInstanceState.getInt(CREATE_KEY);
            mRestart = savedInstanceState.getInt(RESTART_KEY);
            mStart = savedInstanceState.getInt(START_KEY);
            mResume = savedInstanceState.getInt(RESUME_KEY);

        }

        // Emit LogCat message
        Log.i(TAG, "Entered the onCreate() method");

        // TODO:
        // Update the appropriate count variable
        // Update the user interface via the displayCounts() method
        mCreate += 1;
        displayCounts();

    }

    // Lifecycle callback overrides

    @Override
    public void onStart() {
        super.onStart();

        // Emit LogCat message
        Log.i(TAG, "Entered the onStart() method");

        // TODO:
        // Update the appropriate count variable
        // Update the user interface
        mStart += 1;
        displayCounts();

    }

    @Override
    public void onResume() {
        super.onResume();

        // Emit LogCat message
        Log.i(TAG, "Entered the onResume() method");

        // TODO:
        // Update the appropriate count variable
        // Update the user interface
        mResume += 1;
        displayCounts();

    }

    @Override
    public void onPause() {
        super.onPause();

        // Emit LogCat message
        Log.i(TAG, "Entered the onPause() method");
    }

    @Override
    public void onStop() {
        super.onStop();

        // Emit LogCat message
        Log.i(TAG, "Entered the onStop() method");
    }

    @Override
    public void onRestart() {
        super.onRestart();

        // Emit LogCat message
        Log.i(TAG, "Entered the onRestart() method");

        // TODO:
        // Update the appropriate count variable
        // Update the user interface
        mRestart += 1;
        displayCounts();

    }

    @Override
    public void onDestroy() {
        super.onDestroy();

        // Emit LogCat message
        Log.i(TAG, "Entered the onDestroy() method");
    }

    @Override
    public void onSaveInstanceState(Bundle savedInstanceState) {
        super.onSaveInstanceState(savedInstanceState);

        Log.i(TAG, "Entered the onSaveInstanceState() method");
        // TODO:
        // Save state information with a collection of key-value pairs
        // 4 lines of code, one for every count variable
        savedInstanceState.putInt(CREATE_KEY, mCreate);
        savedInstanceState.putInt(RESTART_KEY, mRestart);
        savedInstanceState.putInt(START_KEY, mStart);
        savedInstanceState.putInt(RESUME_KEY, mResume);


    }

    public void onRestoreInstanceState(Bundle savedInstanceState) {
        // Always call the superclass so it can restore the view hierarchy
        super.onRestoreInstanceState(savedInstanceState);

        Log.i(TAG, "Entered the onRestoreInstanceState() method");

        // Restore state members from saved instance
        mResume = savedInstanceState.getInt(RESUME_KEY);
        mRestart = savedInstanceState.getInt(RESTART_KEY);
        mStart = savedInstanceState.getInt(START_KEY);
        mCreate = savedInstanceState.getInt(CREATE_KEY);

        //displayCounts();
    }

    // Updates the displayed counters
    // This method expects that the counters and TextView variables use the
    // names
    // specified above
    public void displayCounts() {

        mTvCreate.setText("onCreate() calls: " + mCreate);
        mTvStart.setText("onStart() calls: " + mStart);
        mTvResume.setText("onResume() calls: " + mResume);
        mTvRestart.setText("onRestart() calls: " + mRestart);

    }
}

here is the xml

<LinearLayout   xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical" >

    <TextView android:id="@+id/create"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="@string/onCreate" />

    <TextView android:id="@+id/start"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="@string/onStart" />

    <TextView android:id="@+id/resume"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="@string/onResume" />

    <TextView android:id="@+id/restart"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="@string/onRestart" />

    <Button android:id="@+id/bLaunchActivityTwo"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="@string/button" />

</LinearLayout>

Solution

  • You are getting the values of mCreate, mStart, mRestart and mResume from the Bundle object twice, in onCreate and in onRestoreInstanceState. This means that any changes to your counts made between retrieving the values the two times will be ignored.

    If it is called at all, onRestoreInstanceState gets called after onCreate, so you should not restore the values in onRestoreInstanceState as they would already have been restored in onCreate.