6

I have a couple of fragments which substitute one for another. The UI of these fragments changes and I need to hold it's new state. So the code looks pretty trivial:

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

    if (mStepTwo == null) {
        mStepTwo = new QuizStepTwo();
        mStepTwo.setListener(mStepTwoListener);
    } else {
        fragmentTransaction.remove(mStepTwo);
    }

    fragmentTransaction.replace(R.id.step_holder, mStepTwo);
    fragmentTransaction.addToBackStack("second_step");

    fragmentTransaction.commit();

However when I replace the second step with the first, for instance by pressing the back-button,- its' UI state rolls back to initial.

How do I hold the state ? OnSaveInstanceState ? or something more comfortable ?

Similar questions: Android Fragment view state within a tab host, How to restore Android fragment view state

Community
  • 1
  • 1
midnight
  • 3,385
  • 3
  • 32
  • 57
  • How big are those UI changes? – user Dec 29 '12 at 08:52
  • a couple of radio group choices or similar- not big actually. – midnight Dec 29 '12 at 08:53
  • I'm not sure I understand at what state are you referring. Do you want to save the state of the fragment that **was** replaced and will become visible when the user clicks the BACK button? Or do you want to save the state of the fragment which will be destroyed by clicking on the BACK button so you can restore its UI when you'll show it again? – user Jan 02 '13 at 14:53
  • `was replaced and will become visible when the user clicks the BACK button`. At this moment I watch backstack changes and call custom method `restoreLayout` from the relevant fragment. Is there platform ready-made solution ? – midnight Jan 03 '13 at 09:14
  • I haven't worked much with transactions yet, but I'd expect the state to be restored automatically by Android... guess not? Anw see my answer. – Oleg Vaskevich Jan 06 '13 at 06:46
  • that's what I did - instance fields. – midnight Jan 06 '13 at 09:15

5 Answers5

3

I haven't used this, so mileage may vary. You could try using the FragmentManager.saveFragmentInstanceState method when replacing Fragments, then use Fragment.setInitialSavedState method when restoring the Fragment. From the docs, it sounds like it may only work if making a new Fragment of the same type, so unsure if this will work with your current implementation.

Jason Robinson
  • 29,432
  • 18
  • 72
  • 128
2

This question (and its solution) looks similar to what you're trying to do.

However, one alternative solution I can think of would be not to replace the first fragment with the second but rather hide it (with fragmentTransaction.hide()), or perhaps detach. That way when the user presses BACK the fragment will be shown and its state will be intact. It might take more memory but it should still work as the fragment will not be destroyed.

Community
  • 1
  • 1
Oleg Vaskevich
  • 11,606
  • 5
  • 55
  • 75
1

If the state depends on the your app data, it's better to save them in SharedPreferences file and use it to build the UI elements.

Nitin Sethi
  • 1,403
  • 1
  • 11
  • 19
  • sharedpreferences are about IO operations. If I go for such an awkward approach I'd better use plain activity fields. – midnight Dec 29 '12 at 09:45
1

Take a look at the Fragment documentation example:

You can use the onSaveInstanceState method to store your state

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

And then retrieve it on the onActivityCreated callback

@Override
public void onActivityCreated(Bundle savedInstanceState) {
    super.onActivityCreated(savedInstanceState);
    if (savedInstanceState != null) {
        // Restore last state for Fragment documentation examplechecked position.
        mCurCheckPosition = savedInstanceState.getInt("curChoice", 0);
    }
}
Robert Estivill
  • 11,585
  • 7
  • 36
  • 60
  • I'm not destroying the activity - just substituting one fragment for another. Despite realizing this won't work I tried it on a very simple example and onSaveInstanceState wasn't called, because there was no reason for it be called(I didn't shutdown the activity). If you have a working example with saveIntanceState - please let me see it. Thanks. – midnight Jan 05 '13 at 08:19
0

The difference between add and replace is when we add the previous fragment is not paused or stopped. where as when we try to replace a fragment the previous one goes through a cycle of pause and stops. but when we put that in stack, the previous fragment is saved on top of stack. And is retrieved and loaded on events such as back-press.

So if your solution needs that your UI should never be stopped or unloaded you should just hide it and add a fragment on top of it. Or if its OK to unload the fragment and the UI can be regenerated with some type of parameters. So you can have some parameter in fragment memory itself determining what stats it should hold. By default it will try to hold some default state. But rest you can created your object and attach it to fragment.

As for onSaveInstanceState, it will be called when the activity containing fragment is closed i.e events such as home press.

e.g

public class MainActivityFragment1 extends Fragment {
    int alreadyCreated = 0;

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

        if (alreadyCreated == 1) { // restoreLayout();
            Log.i("MainActivity", " Fragment already created and can be restored Fragment 1");
        }else
            Log.i("MainActivity", " Running Once Fragment 1");

        alreadyCreated = 1;


    01-07 16:08:07.009: I/MainActivity(14722):  Running Once Fragment 1
    01-07 16:08:09.239: I/MainActivity(14722):  MainActivity I on pause
    01-07 16:08:09.239: I/MainActivity(14722):  MainActivity I on stop
    01-07 16:08:09.239: I/MainActivity(14722):  Running Once Fragment 2
    01-07 16:08:13.499: I/MainActivity(14722):  Back Pressed
    01-07 16:08:13.619: I/MainActivity(14722):  MainActivity II on pause
    01-07 16:08:13.619: I/MainActivity(14722):  MainActivity II on stop

01-07 16:08:13.619: I/MainActivity(14722):  MainActivity II on stop
01-07 16:08:13.619: I/MainActivity(14722):  MainActivity II on stop
01-07 16:08:13.619: I/MainActivity(14722):  Fragment already created and can be restored Fragment 1
Nimish Choudhary
  • 1,998
  • 16
  • 17