Can't keep fragments live through changing orientation or Saving fragment UI

actionbarsherlock, android, android-fragments

Solution

It's not part of the problem but you should be aware that the use of `onSaveInstanceState` is not needed for saving a View state. Android does that for you already as long as there's an ID to the View.

Seems like the problem you are facing is that you are not restoring the fragments from their `FragmentManager`. The fragments are there, but you simply didn't go to the `FragmentManager` and brought them once the `onCreate` has happened again.

This code should go in the `onCreate`:

    // Try and fetch the fragments from the manager
    locationFragement = fragmentManager.findFragmentByTag(LOCATION_FRAGMENT_TAG);
    homeFragment = fragmentManager.findFragmentByTag(HOME_FRAGMENT_TAG);
    settingsFragment = fragmentManager.findFragmentByTag(SETTINGS_FRAGMENT_TAG);

    // If the fragment weren't found - meaning it's the first time the activity was 
    // started, create them
    if (locationFragement == null)  locationFragement = new LocationFragment();
    if (homeFragment == null)       homeFragment = new HomeFragment();
    if (settingsFragment == null)   settingsFragment = new SettingsFragment();

And, whenever you are adding/removing/replacing a fragment, make sure to add him with the TAG, i.e.

    // EXAMPLE HOW TO USE A REPLACE WITH A TAG
    getSupportFragmentManager().beginTransaction().replace(android.R.id.content, 
                                      locationFragement, LOCATION_FRAGMENT_TAG);

Does that work?

Problem

I have an app that uses SherlockActionBar and switches between dynamic fragments through ActionItems in the Action Bar. The problem is that i can't save the fragment states and their UI data. This is the FragmentActivity: ``` public class MainActivity extends SherlockFragmentActivity { private LocationFragment locationFragement; private HomeFragment homeFragment; private SettingsFragment settingsFragment; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); ActionBar actionBar = getSupportActionBar(); actionBar.setDisplayShowTitleEnabled(false); locationFragement = new LocationFragment(); homeFragment = new HomeFragment(); settingsFragment = new SettingsFragment(); } @Override public boolean onCreateOptionsMenu(com.actionbarsherlock.view.Menu menu) { getSupportMenuInflater().inflate(R.menu.main, menu); return true; } @Override public boolean onOptionsItemSelected(MenuItem item) { FragmentManager fragManager = getSupportFragmentManager(); FragmentTransaction fragTransaction = fragManager.beginTransaction(); switch (item.getItemId()){ case R.id.home: fragTransaction.replace(android.R.id.content, homeFragment); break; case R.id.location: fragTransaction.replace(android.R.id.content, locationFragement); break; case R.id.settings: fragTransaction.replace(android.R.id.content, settingsFragment); break; } fragTransaction.commit(); return true; } ``` Firstly, I tried to call to a single instance of the fragments, only to encounter NullPointerExceptions every time i did in the onOptionsItemSelected switch block ``` fragTransaction.replace(android.R.id.content, myFragmentClassName); ``` while the fragment instantiation was under ``` if(savedInstanceState == null){ locationFragement = new LocationFragment(); homeFragment = new HomeFragment(); settingsFragment = new SettingsFragment(); } ``` The fragments would not have created under orientation change obviously, and i couldn't figure anyway i could keep them instantiated. So i decided to create them anew every onCreate (which is bad but i wanted something to work) and save the UI data just to pass it back to the fragment. This is one of the fragments, the other 2 are the same: ``` public class LocationFragment extends SherlockFragment { private View myView; private CheckBox myCheckBok; @Override public void onCreate(Bundle savedInstanceState) { setRetainInstance(true); Log.d("LocationFragment", "onCreate running"); super.onCreate(savedInstanceState); } @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { Log.d("LocationFragment", "onCreateView running"); myView = inflater.inflate(R.layout.map_fragment, container, false); myCheckBok = (CheckBox) myView.findViewById(R.id.mapFragmentCheckBox); if(savedInstanceState != null){ myCheckBok.setChecked(savedInstanceState.getBoolean("isChecked")); } return myView; } @Override public void onResume() { Log.d("LocationFragment", "onResume running"); super.onResume(); } @Override public void onPause() { Log.d("LocationFragment", "onPause running"); super.onPause(); } @Override public void onSaveInstanceState(Bundle outState) { boolean isChecked = myCheckBok.isChecked(); outState.putBoolean("isChecked", isChecked); Log.d("LocationFragment", "onSaved Instant running"); super.onSaveInstanceState(outState); } ``` I'm saving the checkbox's state, when i pass through the icons the checkbox state is saved and also through orientation change. BUT, when i change orientation, press another icon (or press the same one) and return to my fragment, the state isn't saved. I realized this is caused due to onSavedInstanceState not running when i change to another fragment (thus not saving or passing the checkBox data). I haven't found answers anywhere on how to save correctly UI data from fragments (just through savedInstanceState doesn't cut it for my purposes) or how to manage several fragment instantiations while changing them. I know that each time i change a fragment, all it's data is saved automatically by the system, but can't seem to get it to work. Please help.

Original source