2016-10-05 226 views
0

我做了这个类:的Android - 保存/恢复状态FragmentStatePageAdapter

public class My_ViewPagerAdapter extends FragmentStatePagerAdapter { 

    private ArrayList<My_Fragment> fragments=new ArrayList<>(); 
    private ArrayList<String> tabTitles=new ArrayList<>(); 

    public My_ViewPagerAdapter(FragmentManager fm) { 

     super(fm); 
    } 

    @Override 
    public Fragment getItem(int position) { 

     return fragments.get(position); 
    } 

    @Override 
    public int getItemPosition(Object object) { 

     for (int i=0;i<fragments.size();i++){ 

      Class<? extends My_Fragment> clazz= fragments.get(i).getClass(); 

      if (clazz.isInstance(object)){ 

       return i; 
      } 
     } 
     return POSITION_NONE; 
    } 

    @Override 
    public int getCount() { 

     return fragments.size(); 
    } 

    public void addFragment(My_Fragment fragment, String tabTitle){ 

     fragments.add(fragment); 
     tabTitles.add(tabTitle); 
     notifyDataSetChanged(); 
    } 

    public void removeFragment(int position){ 

     fragments.remove(position); 
     tabTitles.remove(position); 
     notifyDataSetChanged(); 
    } 

    public My_Fragment getFragmentAtTab(int position){ 

     return fragments.get(position); 
    } 

    @Override 
    public CharSequence getPageTitle(int position) { 

     return tabTitles.get(position); 
    } 
} 

我添加/删除动态片段/标签,我想通过配置的变化,以挽救他们的状态。

我的onSaveInstanceState实现():

int tabs=tabLayout.getTabCount(); 

    for (int i=0;i<tabs;i++){ 

     outState.putInt("TabsCount",tabs); 
     outState.putString("Tab_"+i,getTabTitle(i)); 
     outState.putString("FragmentClassAtTab_"+i,my_viewPagerAdapter.getFragmentAtTab(i).getClass().getName()); 
    } 

和我实现onRestoreInstanceState():

for (int i=0;i<tabs;i++){ 

     try { 

      My_Fragment fragment= (My_Fragment) Class.forName(savedInstanceState.getString("FragmentClassAtTab_"+i)).newInstance(); 
      addTab(fragment ,savedInstanceState.getString("Tab_"+i)); 
     } 
     catch (ClassNotFoundException e) { 

      e.printStackTrace(); 
     } 
     catch (InstantiationException e) { 

      e.printStackTrace(); 
     } 
     catch (IllegalAccessException e) { 

      e.printStackTrace(); 
     } 
    } 

addTab方法是:

public void addTab(My_Fragment fragment, String title){ 

    if (fragment!=null) my_viewPagerAdapter.addFragment(fragment,title); 
    tabLayout.addTab(tabLayout.newTab().setText(title)); 
} 

该问题:

发生配置更改时,我添加的每个片段都会“自动”重新创建,因此每次都会调用其构造函数。 onCreateView在这些实例上被调用,而不是由我的代码重新创建的那些。

我需要onCreateView才能在我的选项卡中实例化的片段上调用以设置其列表视图。创建

碎片“自动”得到通过我的onRestoreInstanceState方法换成新的片断实例,但没有onCreateView方法被调用这些新的实例。

我认为我做错了,也许有更好的方式来保存标签和片段通过配置更改...任何帮助表示赞赏。

+0

只是为了充分了解,是由一个活动或片段举行的FragmentStatePagerAdapter?配置更改后分片的数量是否正确?他们是否有预期的内容? – cYrixmorten

+0

是的,适配器在我的活动的onCreate()方法中被占用并重新创建。如果说“片段数量”是指fragments.size(),那么是的,我用来通过调用适配器上的“removeFragment”来移除片段,但是因为它在配置更改后重新创建(总是在onCreate方法中)不需要手动删除它们。 – Lazarus

+0

认为我的进一步输入是有限的(离开Android一段时间)。然而,你看了这个SO帖子:http://stackoverflow.com/questions/15313598/once-for-all-how-to-correctly-save-instance-state-of-fragments-in-back-stack?只是认为它看起来相关 – cYrixmorten

回答

0

我曾经创造了类似的东西,这在我的情况是这样的:

public class DisplayPagerAdapter extends FragmentStatePagerAdapter { 

    private static final String TAG = "DisplayPagerAdapter"; 

    SparseArray<DisplayFragment> registeredFragments = new SparseArray<DisplayFragment>(); 

    private final Context context; 
    private final DisplayCoreModule display; 
    private final FragmentManager fm; 

    private boolean isAddOrRemoving; 

    public DisplayPagerAdapter(Context context, FragmentManager fm, 
      DisplayCoreModule display) { 
     super(fm); 
     this.context = context; 
     this.display = display; 
     this.fm = fm; 

     Log.d(TAG, "pages " + display.getPagesCount()); 
    } 


    public void notifySizeChangingDataSetChange() { 
     isAddOrRemoving = true; 
     notifyDataSetChanged(); 
     isAddOrRemoving = false; 
    } 

    @Override 
    public int getCount() { 
     int count = (display != null && display.getPagesCount() > 0) ? display 
       .getPagesCount() : 1; 
     return count; 
    } 

    @Override 
    public int getItemPosition(Object object) { 
     DisplayFragment frag = (DisplayFragment) object; 
     if (!display.containsPageId(frag.getPageId())) { 
      // this will update the 'no information' page with id -1 
      return POSITION_NONE; 
     } 
     if (isAddOrRemoving) { 
      // recreate all for simplicity 
      return POSITION_NONE; 
     } 
     return POSITION_UNCHANGED; 
    } 

    @Override 
    public Fragment getItem(int position) { 
     Log.d(TAG, "getItem " + position); 
     return DisplayFragment.newInstance(position); 
    } 

    @Override 
    public CharSequence getPageTitle(int position) { 
     if (display != null && display.getPagesCount() > 0) { 
      return context.getString(R.string.page) + " " + (position + 1); 
     } else { 
      return super.getPageTitle(position); 
     } 
    } 

    @Override 
    public Object instantiateItem(ViewGroup container, int position) { 
     Log.d(TAG, "instantiateItem " + position); 
     DisplayFragment fragment = (DisplayFragment) super.instantiateItem(
       container, position); 
     registeredFragments.put(position, fragment); 
     return fragment; 
    } 

    @Override 
    public void destroyItem(ViewGroup container, int position, Object object) { 
     Log.d(TAG, "destroyItem " + position); 
     registeredFragments.remove(position); 
     super.destroyItem(container, position, object); 
    } 

    public Fragment getRegisteredFragment(int position) { 
     return registeredFragments.get(position); 
    } 

    public SparseArray<DisplayFragment> getRegisteredFragments() { 
     return registeredFragments; 
    } 

} 

以来,它一直我写了这个很长一段时间,所以无法详谈了。

但是,关键的一点(我会认为)是,我有一个外部'簿记'(DisplayCoreModule)。每当片段数量在DisplayCoreModule中发生变化时,我只需调用notifySizeChangingDataSetChange()即可创建FragmentStatePagerAdapter刷新内容。

通过修正你的一些问题,FragmentStatePagerAdapter将不会调用你的片段的onCreateView,直到它们被显示。通常这意味着只有三个片段:您目前正在查看的片段和片段两侧各有一个片段。

也许,过来想一想,你的问题的根源是缺少getItemPosition()与POSITION_NONE。似乎还记得,要更新动态内容是非常必要的。使notifyDataSetChanged具有适当的效果。

+0

谢谢你的回答!但我认为,只要调用“notifydataSetChanged()”方法,每当我添加/删除tab/fragment与您的方法类似,所以问题仍然存在。 – Lazarus

+0

我明白你的意思。只是看起来有点像你更急切地管理适配器的片段,而我的片段或多或少只会得到一个要求创建实例的计数。我认为那里有区别。还增加了几行可能值得研究的答案。 – cYrixmorten

+0

我添加了getItemPosition()重写的方法,但没有任何帮助...你会建议做别的事情吗?我真的不知道如何使这项工作。 – Lazarus

0

哈克解决方案:

我只是修改了addTab方法:

public void addTab(My_Fragment fragment, String title){ 

    boolean createFragment=true; 

    if (getTabCount()>0){ 
     //all tabs must have different names 
     for (int i=0;i<getTabCount();i++){ 

      if (getTabTitle(i).equals(title)==true){ 

       createFragment=false; 
       break; 
      } 
     } 
    } 

    if (createFragment && fragment!=null){ 
     //this ensures that if a fragment of the same type already exists, that should be the one to be added, tabs are made of fragments of different classes, so there will be no problem while checking this. 
     for (Fragment f: my_activity.getSupportFragmentManager().getFragments()){ 

      if (fragment.getClass().isInstance(f)){ 

       my_viewPagerAdapter.addFragment((My_Fragment)f,title); 
       tabLayout.addTab(tabLayout.newTab().setText(title)); 
       return; 
      } 
     } 
     my_viewPagerAdapter.addFragment(fragment,title); 
     tabLayout.addTab(tabLayout.newTab().setText(title)); 
    } 
}