0

I have one activity and a couple of fragments. My activity has a drawer list that I use to switch fragments and roughly looks like this:

public class MainActivity extends AppCompatActivity
{
    private PreferencesFragment preferencesFragment;
    private HomeFragment homeFragment;

    private void selectMenuItem(position)
    {
        Fragment fragment = null;
        switch (position) {
            case 0:
                if (preferencesFragment == null) {
                    preferencesFragment = new PreferencesFragment();
                }
                fragment = preferencesFragment;
            break;
            case 1:
                if (homeFragment == null) {
                    homeFragment = new HomeFragment();
                }
                fragment = homeFragment;
            break;
        }
        getFragmentManager()
            .beginTransaction()
            .replace(R.id.fragment_container, fragment)
            .commit();

    }
}

So whenever I click on a drawer list item, selectMenuItem is called with the correct position. This loads an existing fragment or creates a new one when needed. The problem is that, even when a fragment already exists, the onCreateView method is triggered in the Fragments. I want to maintain the state of the view and only execute the code in onCreateView once. The docs say this about onCreateView:

The system calls this when it's time for the fragment to draw its user interface for the first time. To draw a UI for your fragment, you must return a View from this method that is the root of your fragment's layout. You can return null if the fragment does not provide a UI.

So why is it being called whenever selectMenuItem is executed? I verified that it's actually not executing the new Fragment() block and loading the properties value. How can I maintain the state of my Fragments when I'm using just 1 activity?

savedInstanceState is also null in the onCreateViewMethod in the Fragments. onSavedInstanceState is never triggered in the Fragments.

jp1987
  • 121
  • 15

2 Answers2

0

Yes, that's how the fragment lifecycle works. replace() removes any existing fragments, and removing a fragment destroys its view. Reusing the same Fragment instance in a later fragment transaction will trigger the lifecycle again from the beginning.

As Ivan mentions in his comments, onSaveInstanceState() only gets triggered when the hosting activity's onSaveInstanceState() is triggered, and merely replacing a fragment within an activity leaves the activity intact. You can save the state yourself, see e.g. android fragment- How to save states of views in a fragment when another fragment is pushed on top of it

To allow your fragments to get garbage collected, consider not keeping references to them.

Community
  • 1
  • 1
laalto
  • 150,114
  • 66
  • 286
  • 303
  • Thanks, that makes sense. I didn't keep references to them before and just used "New HomeFragment();" every time after clicking a menu item. However, onSaveInstanceState() was never called on my Fragments. Any idea why? – jp1987 Sep 03 '15 at 19:04
  • 1
    `onSaveInstanceState()` will not be called when you remove a fragment from layout. It's only for when containing activity's `onSaveInstanceState()` is called. Otherwise, it retains state as it is, unless the activity is killed, and as long as you hold on to the fragment reference, you can assume member variables are intact, only views get destroyed/recreated (And that, of course means, don't forget to `null` member references to views in `onDestroyView()` if any) – Ivan Bartsov Sep 03 '15 at 19:13
  • I added this to my Fragment: `@Override public void onSaveInstanceState(Bundle outState) { super.onSaveInstanceState(outState); Log.v(LOG_TAG, "onSaveInstanceState"); }` But this is never called? I don't have this method overridden in my activity. – jp1987 Sep 03 '15 at 19:17
  • It is actually only called when I turn my screen off. Not when I switch Fragments. – jp1987 Sep 03 '15 at 19:21
0

If you replace fragment with another fragment -- views get destroyed, that's the correct behavior. If you really need to avoid view recreation, you can use FragmentTransaction.hide(), but imho your current approach is right, you don't know whether user will ever want to see PreferencesFragment so no point in bloating memory with unnecessary hidden views.

Ivan Bartsov
  • 19,664
  • 7
  • 61
  • 59