2

I'm trying to understand the process of saving and restoring state using fragments. I've created sliding navigation menu using it.

In one of the fragments there is this code:

public class FifthFragment extends Fragment {

    CheckBox cb;
    View view;

    @Override
    public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {

        view = inflater.inflate(R.layout.fifth_layout, container, false);
        cb = (CheckBox) view.findViewById(R.id.checkBox);
        return view;

    }

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

        if (savedInstanceState != null) {
            // Restore save state
        }

    }

    @Override
    public void onSaveInstanceState(Bundle outState) {
        super.onSaveInstanceState(outState);
        // save state
    }

}

For example I want to save the state of the CheckBox before user exits the fragment and restore it when the fragment is created again. How to achieve this?

EDIT:

According to raxellson's answer I've changed my fragment to this:

public class FifthFragment extends Fragment {

    private static final String CHECK_BOX_STATE = "string";
    CheckBox cb;
    View view;

    @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) {
            Log.i("statenull", "null");
        }
        if (savedInstanceState != null) {
            // Restore last state for checked position.
            boolean checked = savedInstanceState.getBoolean(CHECK_BOX_STATE, false);
            cb.setChecked(checked);
        }

        return view;
    }

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

}

I got logged I/statenull: null so savedInstanceState was not saved. What am I doing wrong?

Godfryd
  • 479
  • 1
  • 7
  • 17

2 Answers2

5

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.

malmling
  • 2,398
  • 4
  • 19
  • 33
  • 2
    It doesn't work for me. I've added `if (savedInstanceState == null) { Log.i("statenull", "null"); }` . And it logs this every time I open that fragment :/ – Godfryd Dec 03 '16 at 15:54
  • So have you stored anything in `onSaveInstanceState` ? update your post with what you have. – malmling Dec 03 '16 at 16:01
  • Yes, this `outState.putBoolean(CHECK_BOX_STATE, cb.isChecked());` . – Godfryd Dec 03 '16 at 16:02
  • Update your post with what you have. @Godfryd – malmling Dec 03 '16 at 16:07
  • I'm using navigation drawer fragments simmilar to [this post](https://stackoverflow.com/questions/23050242/save-the-state-of-navigation-drawer-fragments?rq=1) . Maybe it has something to do with the issue? It must be the problem because I'm creating new fragment every time I click on the menu. – Godfryd Dec 03 '16 at 16:23
  • So when you add the fragment, you always create a new instance of it? I think that might be your problem. You want to add it with a tag so that you can retrieve the same instance of the fragment if it's already added to the fragment manager. – malmling Dec 03 '16 at 16:29
  • Yes I'm creating a new instance every time. How do I add it with a tag? – Godfryd Dec 03 '16 at 16:53
  • You are actually adding it with a tag now, but you don't use it. You should try to retrieve the fragment with that tag and use that exact instance if it's present. so this is what you're missing `fragmentManager.getFragmentByTag(tag)`. Edited my post, added some code to point you in the right direction. – malmling Dec 03 '16 at 16:55
  • onSaveInstanceState() wont always be called when you navigate/destroy a fragment - better explained here: https://stackoverflow.com/a/20892548/4096214. Perhaps consider overriding another method that you're sure (based on how you're navigating between frags) will be called such as onPause/onStop. I've been having this problem and as I have only one small piece of data to store for each fragment (3 key/value pairs total) I am using Shared Preferences to store/retrieve the data in onStop() and onCreateView(). – Burkely91 Jul 31 '17 at 20:18
  • Also consider looking into pushing fragment transactions to the back stack. If you're only going back and forth between fragments you may be able to restore the state of the previous fragment quite easily, check this out: https://stackoverflow.com/questions/11353075/how-can-i-maintain-fragment-state-when-added-to-the-back-stack. As you can see there are a few ways to save and restore states! – Burkely91 Jul 31 '17 at 20:21
0

After see all the example. Here is the solution for save fragment state:

Two steps for this:

1.

String saveValue;
 
 
 @Override
    public void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        if (savedInstanceState == null) {
            saveValue = "";
        } else {

            saveValue = savedInstanceState.getString("saveInstance");
          

        }
    }
@Override
    public void onSaveInstanceState(Bundle savedInstanceState) {
        super.onSaveInstanceState(savedInstanceState);
        //save the values of fragment if destroy on second to back
        if (!saveValue.isEmpty())
            savedInstanceState.putString("saveInstance", saveValue);
       
    }

In onSaveInstanceState you can save your values. And after destroy fragment you can receive your values through onCreate.