Fragment recreated every time after orientation change, unable to restore state

天涯浪子 提交于 2019-12-05 03:05:40

Even though the answer has already been accepted, let me clarify this more: the "issue" is in the Android Studio template. The problem, as pointed out by Edmund, is in the Navigation Drawer calling the menu when recreated, thus re-calling the Fragment. To solve this, I made this slight modification on the NavigationDrawerFragment.java file as proposed by Android Studio. Original:

    @Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    // Read in the flag indicating whether or not the user has demonstrated awareness of the
    // drawer. See PREF_USER_LEARNED_DRAWER for details.
    SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(getActivity());
    mUserLearnedDrawer = sp.getBoolean(PREF_USER_LEARNED_DRAWER, false);

    if (savedInstanceState != null) {
        mCurrentSelectedPosition = savedInstanceState.getInt(STATE_SELECTED_POSITION);
        mFromSavedInstanceState = true;
    }

    // Select either the default item (0) or the last selected item.
    selectItem(mCurrentSelectedPosition);

}

New one:

    @Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    // Read in the flag indicating whether or not the user has demonstrated awareness of the
    // drawer. See PREF_USER_LEARNED_DRAWER for details.
    SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(getActivity());
    mUserLearnedDrawer = sp.getBoolean(PREF_USER_LEARNED_DRAWER, false);

    if (savedInstanceState != null) {
        mCurrentSelectedPosition = savedInstanceState.getInt(STATE_SELECTED_POSITION);
        mFromSavedInstanceState = true;
    } else {
        // Select either the default item (0) or the last selected item.
        selectItem(mCurrentSelectedPosition);
    }
}

Just lost half a production day to figure this out. Hope it may help somebody else.

As updated in the question, this is resolved and thanks again to @Luksprog for pointing out what I overlooked.

The behavior of Fragment actually aligns with Activity classes.

Here is the cause of my issue:

  • The project is created using navigation drawer pattern provided by Android Studio's "create project" wizard. The drawer is implemented in the NavigationDrawerFragment class.
  • The fragment holding the view pager is added when a particular item in the drawer is selected. The code is implemented my home activity.
  • When screen rotates, the onCreate() method of NavigationDrawerFragment is called, preserving last selected item.
  • And here is what went wrong - upon recreation, NavigationDrawerFragment will call selectItem() again, which triggers my menu item selected handler. This causes the ListFragment be replaced.

This can be prevented by checking the active menu item in my menu selection handler code, or by disabling that selectItem() call.

You dont need to handle on savedInstanceState. Because all fragments stored in fragment manger (it like array of fragments) and when the orientation changes activity destroys but fragment manager still hold all fragments that was added before. So you just need to check if fragment was already added.

private void openFragment(Fragment fragment, String tag) {
            FragmentManager fragmentManager = getSupportFragmentManager();
            FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
            Fragment existingFragment = fragmentManager.findFragmentByTag(tag);
            if (existingFragment != null) {
                fragmentTransaction.add(R.id.container, fragment, tag);
                fragmentTransaction.commit();
            }
        }

Try using onCreateView() here instead of onCreate(), which is specific to Fragments and might make a difference.

Override onSaveInstanceState() to store your state, and recover it in onCreateView() using savedInstanceState.get*(). This is how we do it in our apps, and it should work. As @Ari mentioned, make sure to call super.onSaveInstanceState(outState).

class MyFragment extends ListFragment {

    @Override
    public void onSaveInstanceState(Bundle outState) {
        outState.putString(ARG_PAGE, page); 
        super.onSaveInstanceState(outState);
    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        if(savedInstanceState != null){
            if(savedInstanceState.containsKey(ARG_PAGE)){
                page = savedInstanceState.getInteger(ARG_PAGE);
            }
        }
    }
}

In AndroidManifest.xml add

<activity android:name=".MainActivity"
android:configChanges="orientation|screenSize">
</activity>
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!