2

I have an activity with fragment. Fragment adds to activity like this, depending on some data:

@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
    if (savedInstanceState == null) {
        switch (someId) {
            case 1:
                mFragment = new Fragment1();
                break;
            case 2:
                mFragment = new Fragment2();
                break;
        }
    }

    if (savedInstanceState != null) {
        Log.e("onSaveInstanceState Activity", "not null");
        mFragment = getFragmentManager().getFragment(savedInstanceState, "mFragment");
    }

    Bundle args = new Bundle();
    args.putString(SOME_TEXT, "example text");
    mFragment.setArguments(args);
    if (savedInstanceState == null) {
        FragmentTransaction fragmentTransaction = getFragmentManager().beginTransaction();
        fragmentTransaction.add(R.id.content_frame, mFragment);
        fragmentTransaction.commit();
    }
}

@Override
public void onSaveInstanceState(Bundle outState) {
    super.onSaveInstanceState(outState);
    Log.e("onSaveInstanceState Activity", "onSave");
    getFragmentManager().putFragment(outState, "mFragment", mFragment);
}

And then in fragments (assume they are identical):

@Override
public void onActivityCreated(Bundle savedInstanceState) {
    super.onActivityCreated(savedInstanceState);
    final Activity activity = getActivity();
    setRetainInstance(true);
    Bundle in = getArguments();
    String field1Text = in.getString(SOME_TEXT);
    field1 = (EditText) activity.findViewById(R.id.field1);
    if (savedInstanceState != null) {
        Log.e("savedInstanceState", "not null");
        field1.setText(savedInstanceState.getString("field1"));
    } else {
        Log.e("savedInstanceState", "null");
        field1.setText(field1Text);
    }

@Override
public void onSaveInstanceState(Bundle outState) {
    Log.e("onSaveInstanceState", "onSave");
    outState.putString("field1", field1.getText().toString());
    super.onSaveInstanceState(outState);
}

So I thought that fragment would restore its state and setText to EditText field. But for example when I instantiate fragment with bundle's SOME_TEXT = "example text", then change it to "some changes" in EditText's field, then I move to other app (causing my app to close when memory is low for example):

onSaveInstanceState onSave

is called but onSaveInstanceState Activity is not.

and when I open it again text in EditText is "example text" and in logs I have:

savedInstanceState not null savedInstanceState null

(It seems that onActivityCreated is fired twice in my case) but onSaveInstanceState Activity not null is not called.

so why that text is not as same as I want.

How should I do to restore EditText's field?

Sabre
  • 4,131
  • 5
  • 36
  • 57

3 Answers3

1

In your onCreate() for the activity, you must call the super function. That re-attaches fragments from the SavedInstanceState.

Notice you are performing a second fragment transaction after the re-attachment. You are manually pulling the saved fragment out of the bundle and re-attaching it. You don't need to do that.

That's the problem because a fragment added through a fragment transaction will receive a null savedInstanceState bundle. Meaning the fragment will have no state to implement in it's onCreate(). You can just skip doing any fragment transaction in the onCreate when savedInstanceState != null. And make sure to call the super.onCreate() in the fragment as well.

NameSpace
  • 10,009
  • 3
  • 39
  • 40
  • Now I skip all transactions if `saveInstanceState != null`. But when I move to other app `saveInstanceState` in my activity not called (`savedInstanceState` in fragment is called). Please, see updated question. – Sabre Aug 11 '14 at 11:56
  • Not sure why your activity savedInstance isn't being called (double check that?). But besides that you can remove getFragmentManager().putFragment(outState, "mFragment", mFragment); Calling the super in SavedInstanceState saves the fragment for you. – NameSpace Aug 11 '14 at 12:02
  • I checked `void onSaveInstanceState` in my other activity with fragment (implemented like in my question) and it's called when I move to other app. And that behaviour described in my question is strange and I have no idea why is it so. – Sabre Aug 11 '14 at 12:16
0

I wish I could comment, yet here is my suggestion: Are you sure that

savedInstanceState null

is called inside "first" fragment? I mean, don't you accidently create another fragment which replaces the old one?

Atatakai Neko
  • 86
  • 1
  • 5
  • I think that you are right. New fragment replaces old one (which restored text). But how can I avoid that? That is the question. – Sabre Aug 11 '14 at 11:04
  • Well, it depends on when you instantiate fragments. If it is inside onCreate method in the Activity, you can use such approach: `onCreate(Bundle savedInstance){ if(savedInstance == null){ //perform setup } }` – Atatakai Neko Aug 11 '14 at 11:08
  • It's inside onCreate. I tried to do [like here](http://stackoverflow.com/questions/15313598/once-for-all-how-to-correctly-save-instance-state-of-fragments-in-back-stack). But when I move to other app `onSaveInstanceState` in Activity is not called. – Sabre Aug 11 '14 at 11:24
  • Updated my question with `onSaveInstanceState` from activity. – Sabre Aug 11 '14 at 11:32
0

In the OnCreate() method following the super call you need to add

this.setRetainInstance(true);

That will allow the fragment to retain the state and should save any changes that have been made.

Also in a fragment it's not the onCreate method that does the initial load it is the onCreateView() method.

venom2124
  • 168
  • 9
  • Views that don't use setRetainInstance(true) also keep their view states when saved by SaveInstanceState (e.g. View hierarchy, child fragments, textView text, etc). – NameSpace Aug 11 '14 at 12:14
  • When I move to other app `onSaveInstanceState` in my activity not called (`onSaveInstanceState` in fragment is called). Do you have any ideas why is it so? – Sabre Aug 11 '14 at 12:18