android fragment- How to save states of views in a fragment when another fragment is pushed on top of it

In android, a fragment (say FragA) gets added to the backstack and another fragment (say FragB) comes to the top. Now on hitting back FragA comes to the top and the onCreateView() is called. Now I had FragA in a particular state before FragB got pushed on top of it.

My Question is how can I restore FragA to its previous state ? Is there a way to save state (like say in a Bundle) and if so then which method should I override ?


Solution 1:

In fragment guide FragmentList example you can find:

@Override
public void onSaveInstanceState(Bundle outState) {
    super.onSaveInstanceState(outState);
    outState.putInt("curChoice", mCurCheckPosition);
}

Which you can use later like this:

@Override
public void onActivityCreated(Bundle savedInstanceState) {
    super.onActivityCreated(savedInstanceState);
    if (savedInstanceState != null) {
        // Restore last state for checked position.
        mCurCheckPosition = savedInstanceState.getInt("curChoice", 0);
    }
}

I'm a beginner in Fragments but it seems like solution of your problem ;) OnActivityCreated is invoked after fragment returns from back stack.

Solution 2:

Fragment's onSaveInstanceState(Bundle outState) will never be called unless fragment's activity call it on itself and attached fragments. Thus this method won't be called until something (typically rotation) force activity to SaveInstanceState and restore it later. But if you have only one activity and large set of fragments inside it (with intensive usage of replace) and application runs only in one orientation activity's onSaveInstanceState(Bundle outState) may not be called for a long time.

I know three possible workarounds.

The first:

use fragment's arguments to hold important data:

public class FragmentA extends Fragment {
    private static final String PERSISTENT_VARIABLE_BUNDLE_KEY = "persistentVariable";

    private EditText persistentVariableEdit;

    public FragmentA() {
        setArguments(new Bundle());
    }

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

        persistentVariableEdit = (EditText) view.findViewById(R.id.editText);

        TextView proofTextView = (TextView) view.findViewById(R.id.textView);

        Bundle mySavedInstanceState = getArguments();
        String persistentVariable = mySavedInstanceState.getString(PERSISTENT_VARIABLE_BUNDLE_KEY);

        proofTextView.setText(persistentVariable);


        view.findViewById(R.id.btnPushFragmentB).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                getFragmentManager()
                        .beginTransaction()
                        .replace(R.id.frameLayout, new FragmentB())
                        .addToBackStack(null)
                        .commit();
            }
        });

        return view;
    }

    @Override
    public void onPause() {
        super.onPause();
        String persistentVariable = persistentVariableEdit.getText().toString();

        getArguments().putString(PERSISTENT_VARIABLE_BUNDLE_KEY, persistentVariable);
    }
}

The second but less pedantic way - hold variables in singletons

The third - don't replace() fragments but add()/show()/hide() them instead.

Solution 3:

Just notice that if you work with Fragments using ViewPager, it's pretty easy. You only need to call this method: setOffscreenPageLimit().

Accordign to the docs:

Set the number of pages that should be retained to either side of the current page in the view hierarchy in an idle state. Pages beyond this limit will be recreated from the adapter when needed.

Similar issue here