74

I am trying to save data across orientation changes. As demonstrated in the code below, I use onSaveInstanceState() and onRestoreInstanceState(). I try to get the saved value and I check if it is the correct value in onRestoreInstanceState(). But when I try to use the new value in onCreate(), I don't have the new value but the old one.

protected void onSaveInstanceState(Bundle outState) {
        super.onSaveInstanceState(outState);
        outState.putString("TEXT", user);

    }
protected void onRestoreInstanceState(Bundle savedInstanceState) {
    super.onRestoreInstanceState(savedInstanceState);
    savedUser = savedInstanceState.getString("TEXT");
    Log.d("enregistred value", savedUser);

}



public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        int display_mode = getResources().getConfiguration().orientation;

        if (display_mode == 1) {

            setContentView(R.layout.main_grid);
            mGrid = (GridView) findViewById(R.id.gridview);
            mGrid.setColumnWidth(95);
            mGrid.setVisibility(0x00000000);
            // mGrid.setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION);

        } else {
            setContentView(R.layout.main_grid_land);
            mGrid = (GridView) findViewById(R.id.gridview);
            mGrid.setColumnWidth(95);
            Log.d("Mode", "land");
            // mGrid.setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION);

        }
        Log.d("savedUser", savedUser);
        if (savedUser.equals("admin")) { //value 0
            adapter.setApps(appManager.getApplications());
        } else if (savedUser.equals("prof")) { //value 1
            adapter.setApps(appManager.getTeacherApplications());
        } else {// default value
            appManager = new ApplicationManager(this, getPackageManager());
            appManager.loadApplications(true);
            bindApplications();
        }
}
JDJ
  • 4,298
  • 3
  • 25
  • 44
Zizou
  • 1,891
  • 3
  • 15
  • 16
  • 1
    possible duplicate of [onSaveInstanceState () and onRestoreInstanceState ()](http://stackoverflow.com/questions/4096169/onsaveinstancestate-and-onrestoreinstancestate) – Alex Cohn Dec 07 '13 at 17:37

4 Answers4

58

When your activity is recreated after it was previously destroyed, you can recover your saved state from the Bundle that the system passes your activity. Both the onCreate() and onRestoreInstanceState() callback methods receive the same Bundle that contains the instance state information.

Because the onCreate() method is called whether the system is creating a new instance of your activity or recreating a previous one, you must check whether the state Bundle is null before you attempt to read it. If it is null, then the system is creating a new instance of the activity, instead of restoring a previous one that was destroyed.

static final String STATE_USER = "user";
private String mUser;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    // Check whether we're recreating a previously destroyed instance
    if (savedInstanceState != null) {
        // Restore value of members from saved state
        mUser = savedInstanceState.getString(STATE_USER);
    } else {
        // Probably initialize members with default values for a new instance
        mUser = "NewUser";
    }
}

@Override
public void onSaveInstanceState(Bundle savedInstanceState) {
    savedInstanceState.putString(STATE_USER, mUser);
    // Always call the superclass so it can save the view hierarchy state
    super.onSaveInstanceState(savedInstanceState);
}

http://developer.android.com/training/basics/activity-lifecycle/recreating.html

JusMe
  • 278
  • 1
  • 7
Arvis
  • 8,273
  • 5
  • 33
  • 46
  • @DataDino the documentation linked in Arvis's answer shows that the super call passes along the saved instance bundle by calling super last. If you called super first, you'd leave the instance state as a copy of the bundle at the end of procedure call with no data passed to the activity instance. Java is by value, not by reference. :) A very hard lesson I learned coming from .NET. – DoctorD Jun 19 '17 at 02:48
  • @DoctorD, Whoops! You are correct. I blame it on a lack of caffeine. – DataDino Jun 19 '17 at 02:56
  • @DataDino, Always a good answer. If only Android Studio came packed with caffeine :) – DoctorD Jun 19 '17 at 03:01
  • Notice though, that instead of checking if the state is null during onCreate(), I prefer to implement onRestoreInstanceState(). This is called after onStart() method only if there is a saved state to restore! You don't need to check for null, which is great – Shahar G. Aug 13 '18 at 11:56
23
  • onSaveInstanceState() is a method used to store data before pausing the activity.

Description : Hook allowing a view to generate a representation of its internal state that can later be used to create a new instance with that same state. This state should only contain information that is not persistent or can not be reconstructed later. For example, you will never store your current position on screen because that will be computed again when a new instance of the view is placed in its view hierarchy.

  • onRestoreInstanceState() is method used to retrieve that data back.

Description : This method is called after onStart() when the activity is being re-initialized from a previously saved state, given here in savedInstanceState. Most implementations will simply use onCreate(Bundle) to restore their state, but it is sometimes convenient to do it here after all of the initialization has been done or to allow subclasses to decide whether to use your default implementation. The default implementation of this method performs a restore of any view state that had previously been frozen by onSaveInstanceState(Bundle).

Consider this example here:
You app has 3 edit boxes where user was putting in some info , but he gets a call so if you didn't use the above methods what all he entered will be lost.
So always save the current data in onPause() method of Activity as a bundle & in onResume() method call the onRestoreInstanceState() method .

Please see :

How to use onSavedInstanceState example please

http://www.how-to-develop-android-apps.com/tag/onrestoreinstancestate/

Community
  • 1
  • 1
Shreyos Adikari
  • 12,348
  • 19
  • 73
  • 82
  • can you give me an example please. Because i know that when i change orientation, i call onDestroy then Oncreat, so how can i use the saved valu in Oncreat. – Zizou May 27 '13 at 09:07
  • Please see the above links – Shreyos Adikari May 27 '13 at 09:13
  • 1
    Are you sure that you need to save the text in the edit boxes? The doc says: "The default implementation takes care of most of the UI per-instance state for you by calling onSaveInstanceState() on each view in the hierarchy that has an id... " – Antonio Sesto Mar 10 '15 at 13:13
  • 1
    @AntonioSesto you are correct. From Android Docs: "By default, the system uses the Bundle instance state to save information about each View object in your activity layout (such as the text value entered into an EditText object). So, if your activity instance is destroyed and recreated, the state of the layout is restored to its previous state with no code required by you." – bcorso Jun 22 '15 at 19:24
10

This happens because you use the savedValue in the onCreate() method. The savedValue is updated in onRestoreInstanceState() method, but onRestoreInstanceState() is called after the onCreate() method. You can either:

  1. Update the savedValue in onCreate() method, or
  2. Move the code that use the new savedValue in onRestoreInstanceState() method.

But I suggest you to use the first approach, making the code like this:

public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    int display_mode = getResources().getConfiguration().orientation;

    if (display_mode == 1) {

        setContentView(R.layout.main_grid);
        mGrid = (GridView) findViewById(R.id.gridview);
        mGrid.setColumnWidth(95);
        mGrid.setVisibility(0x00000000);
        // mGrid.setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION);

    } else {
        setContentView(R.layout.main_grid_land);
        mGrid = (GridView) findViewById(R.id.gridview);
        mGrid.setColumnWidth(95);
        Log.d("Mode", "land");
        // mGrid.setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION);

    }
    if (savedInstanceState != null) {
        savedUser = savedInstanceState.getString("TEXT");
    } else {
        savedUser = ""
    }
    Log.d("savedUser", savedUser);
    if (savedUser.equals("admin")) { //value 0
        adapter.setApps(appManager.getApplications());
    } else if (savedUser.equals("prof")) { //value 1
        adapter.setApps(appManager.getTeacherApplications());
    } else {// default value
        appManager = new ApplicationManager(this, getPackageManager());
        appManager.loadApplications(true);
        bindApplications();
    }
}
Eric Wu
  • 101
  • 1
  • 3
1

In most cases, you should not need to override these methods. If you want to override these , do not forget to call super.onSaveInstanceState / super.onRestoreInstanceState

Important Note from documentation

The default implementation takes care of most of the UI per-instance state for you by calling View.onSaveInstanceState() on each view in the hierarchy that has an id, and by saving the id of the currently focused view (all of which is restored by the default implementation of onRestoreInstanceState(Bundle)). If you override this method to save additional information not captured by each individual view, you will likely want to call through to the default implementation, otherwise be prepared to save all of the state of each view yourself.

Check if the information you want to preview is part of a view that may have an ID. Only those with an ID will be preserved automatically.

If you want to Save the attribute of the state which is not being saved already. Then you override these methods and add your bit.

protected void onSaveInstanceState (Bundle outState)

protected void onRestoreInstanceState (Bundle savedInstanceState)

In latest SDK versions Bundle parameter is not null, so onRestoreInstanceState is called only when a savedStateIsAvailable.

However, OnCreate as well gets savedState Parameter. But it can be null first time, so you need to differentiate between first call and calls later on.

Sandeep Dixit
  • 799
  • 7
  • 12