在FragmentTransaction.replace()后面跟着后退button之后,ViewPager Fragments不会被重新创build

我正在尝试实现保存和恢复状态,但是当用PreferenceFragmentreplace主Fragment然后点击后退button时,我遇到了问题。 我的主要Fragment由一个ViewPager和一个带有3个Fragments Fragment组成。 点击后退button后,我的3 FragmentFragment.onCreateView()callback将不会被调用。 我尝试了所有的解决scheme,但是我一直没能解决这个问题。

另一个可能很重要的要注意的是,我的3 ViewPager Fragment的数据存储在单独的类中,这些类是通过Activity实例化和访问的。 3 Fragment都包含RecyclerView列出相当数量的数据。 这是为了清洁,但也使这些数据坚持在Activity 。 这可能不是一个问题,因为它启动应用程序时工作正常,但也因为主要问题是我的Fragments不重新创build。

意外的行为:

在创build应用程序时,一切正常,但是当我用另一个replace我的主要Fragment (包含ViewPagerFragmentPagerAdapter ),然后按下后退button, ViewPager中的Fragment s不会重新创build。 我的主要FragmentonCreateView() 调用。

问题:

我错过了什么? 是否还有其他一些应该创build的callback? 在哪里以及如何重buildFragments

我试过了什么:

  1. 改变了FragmentAdapter在使用,但我真的应该使用getSupportFragmentManager()就像这里的解决scheme。

编辑:使用错误的FragmentManager实际上我的烦恼的来源。 看到我的答案在下面。

  1. 如此处所示,将@Override public int getItemPosition(Object object) {return POSITION_NONE;}FragmentPagerAdapter
  2. 据我所知,从FragmentPagerAdapter更改为FragmentPagerAdapter ,这在这里应该不重要。 FragmentStatePagerAdapter的内部实际上保留了Fragments ,但是它们不会被重新渲染。
  3. 当它的onCreateView()被调用的时候,使用FragmentTransaction把这个主Fragment添加回来,在这个Fragment的其他几个callback中,请看下面的MMMainFragment
  4. 各种其他的东西。

我的MainFragment类与相应的XML布局

 public class MMMainFragment extends Fragment { private MMViewPager mMMViewPager = null; @Nullable @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { // Note that this method IS called when the back button is pressed. // I have tried setting the content back to this instance in several places. View view = inflater.inflate(R.layout.mm_main_fragment, container, false); // Setup ViewPager. mMMViewPager = (MMViewPager) view.findViewById(R.id.mm_pager); TabLayout tabLayout = (TabLayout) view.findViewById(R.id.mm_tablayout); tabLayout.setupWithViewPager(mMMViewPager); return view; } public MMViewPager getMMViewPager() { return mMMViewPager; } } 

mm_main_fragment.xml

 <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" android:orientation="vertical" android:layout_width="match_parent" android:layout_height="match_parent" > <android.support.design.widget.TabLayout android:id="@+id/mm_tablayout" android:layout_width="match_parent" android:layout_height="wrap_content" app:tabMode="scrollable" /> <com.mycompany.myapp.gui.mmpager.MMViewPager android:id="@+id/mm_pager" android:layout_width="match_parent" android:layout_height="match_parent" android:layout_weight="1" /> </LinearLayout> 

然后,在Activity.onCreate()我只是做:

 // Insert Main Fragment. FragmentManager fragmentManager = getSupportFragmentManager(); fragmentManager.beginTransaction() .replace(R.id.mm_content_frame, new MMMainFragment()) .commit(); 

其中mm_content_frame是一个FrameLayout ,我replace和删除Fragment 。 然后,当按下一个button来查看偏好时,我在下面的Activity运行下面的代码片段。 我将这个Fragment添加到后台可以使用后退button。

 public void showSettingsFragment() { getSupportActionBar().setTitle(getString(R.string.mm_drawer_settings)); getSupportFragmentManager().beginTransaction() .replace(R.id.mm_content_frame, new MMPreferencesFragment(), FragmentConstants.SETTINGS_FRAGMENT_TAG) .addToBackStack(null) .commit(); } 

MMViewPager类:

 public class MMViewPager extends ViewPager { private MMActivity mMMActivity; private MMPagerAdapter mMMPagerAdapter; public MMViewPager(Context context, AttributeSet attrs) { super(context, attrs); mMMActivity = (MMActivity) context; mMMPagerAdapter = new MMPagerAdapter(mMMActivity.getSupportFragmentManager(), mMMActivity); this.setOffscreenPageLimit(PagerConstants.OFFSCREEN_PAGE_LIMIT); this.setAdapter(mMMMPagerAdapter); this.setCurrentItem(PagerConstants.PAGE_FILTER_RECIPES); } } 

MMPagerAdapter类,当前是FragmentStatePagerAdapter

 public class MMPagerAdapter extends FragmentStatePagerAdapter { private MMActivity mMMActivity; public MMPagerAdapter(FragmentManager fragmentManager, MMActivity mmActivity) { super(fragmentManager); mMMActivity = mmActivity; } @Override public Fragment getItem(int position) { switch (position) { case PagerConstants.PAGE_FILTER_RECIPES: return new FilteredRecipesFragment(); case PagerConstants.PAGE_SELECTED_RECIPES: return new SelectedRecipesFragment(); case PagerConstants.PAGE_SHOPPING_LIST: return new ShoppingListFragment(); default: return null; } } @Override public int getCount() { return PagerConstants.NUMBER_OF_PAGES; // 3 } @Override public CharSequence getPageTitle(int position) { switch (position) { case PagerConstants.PAGE_FILTER_RECIPES: return mMMActivity.getResources().getString(R.string.mm_title_recipe_filter_fragment); case PagerConstants.PAGE_SELECTED_RECIPES: return mMMActivity.getResources().getString(R.string.mm_title_selected_recipes_fragment); case PagerConstants.PAGE_SHOPPING_LIST: return mMMActivity.getResources().getString(R.string.mm_title_shopping_list_fragment); default: return "Tab"; } } } 

作为参考,这里也是Activity的主要布局:

 <?xml version="1.0" encoding="utf-8"?> <android.support.v4.widget.DrawerLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" android:id="@+id/mm_drawer_layout" android:layout_width="match_parent" android:layout_height="match_parent"> <!-- Source: http://developer.android.com/training/implementing-navigation/nav-drawer.html --> <!-- The main content view --> <RelativeLayout android:layout_width="match_parent" android:layout_height="match_parent"> <!-- Source: http://android-developers.blogspot.in/2014/10/appcompat-v21-material-design-for-pre.html --> <android.support.v7.widget.Toolbar xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/mm_toolbar" android:layout_width="match_parent" android:layout_height="wrap_content" android:minHeight="?attr/actionBarSize" android:layout_alignParentTop="true" style="@style/MMActionBar" app:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar" app:popupTheme="@style/ThemeOverlay.AppCompat.Light" /> <!-- The FrameLayout where I replace Fragments --> <FrameLayout android:id="@+id/mm_content_frame" android:layout_width="match_parent" android:layout_height="match_parent" android:layout_below="@id/mm_toolbar"/> </RelativeLayout> <ListView android:id="@+id/mm_drawer_listview" android:layout_width="260dp" android:layout_height="match_parent" android:paddingLeft="16dp" android:paddingRight="16dp" android:paddingStart="16dp" android:layout_gravity="start" android:choiceMode="singleChoice" android:divider="@android:color/transparent" android:dividerHeight="0dp" android:background="@color/mm_white" /> </android.support.v4.widget.DrawerLayout> 

Solutions Collecting From Web of "在FragmentTransaction.replace()后面跟着后退button之后,ViewPager Fragments不会被重新创build"

经过几天的努力之后,我意识到问题实际上我把错误的FragmentManager传递给了ViewPager 。 这确实是应该使用Fragment.getChildFragmentManager()返回的Fragment.getChildFragmentManager() 。 这是有道理的,因为它是Fragment本身,它将子Fragment的状态存储在ViewPager 。 我不知道为什么我不能做这个工作,但现在的应用LifeCycle工作正常,在我的主要FragmentonCreate()方法下面的设置:

 @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { View view = inflater.inflate(R.layout.mm_main_fragment, container, false); mMMActivity = (MMActivity) container.getContext(); mMMActivity.getSupportActionBar().setTitle(getString(R.string.mm_toolbar_title_main_fragment)); // Setup ViewPager. mViewPager = (ViewPager) view.findViewById(R.id.mm_pager); mAdapter = new MMPagerAdapter(getChildFragmentManager(), mMMActivity); // <-- This is the key mViewPager.setAdapter(mAdapter); mViewPager.setOffscreenPageLimit(PagerConstants.OFFSCREEN_PAGE_LIMIT); mViewPager.setCurrentItem(PagerConstants.PAGE_FILTER_RECIPES); // Setup TabLayout. TabLayout tabLayout = (TabLayout) view.findViewById(R.id.mm_tablayout); tabLayout.setupWithViewPager(mViewPager); return view; } 

这也是另一个问题的解决办法。 作为一个方面的说明,我使用这个解决scheme来获取我的ViewPagerFragment ,它的LifeCycle工作得很好。

testing应用:

在这个问题的研究中,我为此创build了一个testing应用程序。 有兴趣的人可以从这里克隆它。 它有难看的颜色。

据我所知,你已经解决了你的问题。 过去我也遇到过类似的问题。 也许这有助于他人尝试类似的东西。

帮助我保留我的碎片状态的东西是取代了

 @Override public Fragment getItem(int position) { switch (position) { case PagerConstants.PAGE_FILTER_RECIPES: return new FilteredRecipesFragment(); case PagerConstants.PAGE_SELECTED_RECIPES: return new SelectedRecipesFragment(); case PagerConstants.PAGE_SHOPPING_LIST: return new ShoppingListFragment(); default: return null; } } 

我的适配器的方法。

我更改Adapter ,以保持FragmentHashMap 。 这样片段被创build一次,然后从HashMap中检索。 根据您的结构,您可以使用ArrayList而不是HashMap。

这是以一种高效的“聪明”的方式来实现getItemPosition(Object object)return POSITION_NONE; 或物品的正确位置。

我不记得是否有适配器中的getChildFragmentManager

我想我可以挖掘到我的文件系统,如果你需要更多的信息:)