How to Correctly Save Instance State of Fragments in Back Stack

How to correctly save instance state of Fragments in back stack?

To correctly save the instance state of Fragment you should do the following:

1. In the fragment, save instance state by overriding onSaveInstanceState() and restore in onActivityCreated():

class MyFragment extends Fragment {

@Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
...
if (savedInstanceState != null) {
//Restore the fragment's state here
}
}
...
@Override
public void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);

//Save the fragment's state here
}

}

2. And important point, in the activity, you have to save the fragment's instance in onSaveInstanceState() and restore in onCreate().

class MyActivity extends Activity {

private MyFragment

public void onCreate(Bundle savedInstanceState) {
...
if (savedInstanceState != null) {
//Restore the fragment's instance
mMyFragment = getSupportFragmentManager().getFragment(savedInstanceState, "myFragmentName");
...
}
...
}

@Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);

//Save the fragment's instance
getSupportFragmentManager().putFragment(outState, "myFragmentName", mMyFragment);
}

}

Saving and restoring state using fragments

You want to save the value of your current checked state in onSaveInstanceState.

Something like this:

@Override
public void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
outState.putBoolean(CHECK_BOX_STATE, cb.getChecked());
}

and then when your view is created you want to get the value if it's present. And set your CheckBox state with it.

@Override
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fifth_layout, container, false);

cb = (CheckBox) view.findViewById(R.id.checkBox);
if (savedInstanceState != null) {
// Restore last state for checked position.
boolean checked = savedInstanceState.getBoolean(CHECK_BOX_STATE, false);
cb.setChecked(checked);
}

return view;
}

EDIT:

When you add the fragment, make sure to add it with a tag or id so that you can retrieve the same instance.

You could do a helper method to retrieve fragment and set the fragment.

private void setFragment(String tag, Fragment newFragment) {
FragmentManager fm = getSupportFragmentManager();
Fragment savedFragment = fm.getFragmentByTag(tag);
fm.replace(R.id.container, savedFragment != null ? savedFragment : newFragment, tag);
fm.commit();
}

so you your switch you can call the helper method instead.

switch (position) {
case 0:
setFragment("A", new FragmentA());
break;
....
}

Note: This is just an example not best practice since you are creating new fragments every time in your switch case now anyways. But it might point you in the right direction.

How to save state in fragment

Instead of restoring the state during onCreate() you may choose to implement onRestoreInstanceState(), which the system calls after the onStart() method. The system calls onRestoreInstanceState() only if there is a saved state to restore, so you do not need to check whether the Bundle is null.

FYI : this is a sample code. Just for your reference.

public class MainFragment extends Fragment {
private String title;
private double rating;
private int year;

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

savedInstanceState.putString(TITLE, "Gladiator");
savedInstanceState.putDouble(RATING, 8.5);
savedInstanceState.putInt(YEAR, 2000);
}

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

title = savedInstanceState.getString(TITLE);
rating = savedInstanceState.getDouble(RATING);
year = savedInstanceState.getInt(YEAR);
}
}

FYI : This really a good thread check this also Once for all, how to correctly save instance state of Fragments in back stack?

Unable to save Fragment state with onSaveInstanceState

I solved it, the problem was here

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


FragmentManager fragmentManager = getSupportFragmentManager();
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();

if (savedInstanceState != null) {
dataFragment = (InputDataFragment) getSupportFragmentManager().getFragment(savedInstanceState, "dataFragment");
} else {
dataFragment = new InputDataFragment();
}

fragmentTransaction.add(R.id.container, dataFragment);
fragmentTransaction.commit();
}

When I'm in ResultsFragment and rotate the device, Activity onCreate method is called. Even though I got the previous InputDataFragment back from Bundle, calling FragmentTransaction.add() caused the loss of the data.

Moving FragmentTransaction code to the case where savedInstanceState == null was the solution.

How can I maintain fragment state when added to the back stack?

If you return to a fragment from the back stack it does not re-create the fragment but re-uses the same instance and starts with onCreateView() in the fragment lifecycle, see Fragment lifecycle.

So if you want to store state you should use instance variables and not rely on onSaveInstanceState().

Android Fragment not saving UI State on pressing Back Button

Is there any particular reason why you are replacing the fragment? If not, you can just simply add it instead of replacing and that will ensure the state gets maintained.

Your code will change like this

   .add(R.id.container, SecondFragment.newInstance())
.addToBackStack(null)
.commit()


Related Topics



Leave a reply



Submit