Android FragmentStatePagerAdapter,如何标记片段以便稍后查找

当使用FragmentStatePageAdapter我得到这样的片段:

  @Override public Fragment getItem(int position) { return new SuperCoolFragment(); } 

然而,后来我的代码,我需要find这个片段来设置一个属性。 在我使用片段的应用程序的其他部分,我基本上标记它们,并使用findFragmentByTag(TAG)来查找它们,但现在我不知道该怎么做。

如何使用FragmentStatePageAdapterfindFragmentStatePageAdapter

Solutions Collecting From Web of "Android FragmentStatePagerAdapter,如何标记片段以便稍后查找"

*编辑*

正如@ElliotM指出的,有一个更好的解决scheme。 不需要改变你的适配器中的任何东西,只要得到的片段:

 Fragment myFragment = (Fragment) adapter.instantiateItem(viewPager, viewPager.getCurrentItem()); 

*旧的解决scheme*

最好的select是这里的第二个解决scheme: http : //tamsler.blogspot.nl/2011/11/android-viewpager-and-fragments-part-ii.html

简而言之:您可以跟踪所有“活动”片段页面。 在这种情况下,您可以跟踪由ViewPager使用的FragmentStatePagerAdapter中的片段页面。

 public Fragment getItem(int index) { Fragment myFragment = MyFragment.newInstance(); mPageReferenceMap.put(index, myFragment); return myFragment; } 

为了避免引用“不活动”的片段页面,我们需要实现FragmentStatePagerAdapter的destroyItem(…)方法:

 public void destroyItem(View container, int position, Object object) { super.destroyItem(container, position, object); mPageReferenceMap.remove(position); } 

…当你需要访问当前可见的页面,然后你打电话给:

 int index = mViewPager.getCurrentItem(); MyAdapter adapter = ((MyAdapter)mViewPager.getAdapter()); MyFragment fragment = adapter.getFragment(index); 

… MyAdapter的getFragment(int)方法看起来像这样:

 public MyFragment getFragment(int key) { return mPageReferenceMap.get(key); } 

—编辑:

在你的适配器中添加这个,在改变方向之后:

 /** * After an orientation change, the fragments are saved in the adapter, and * I don't want to double save them: I will retrieve them and put them in my * list again here. */ @Override public Object instantiateItem(ViewGroup container, int position) { MyFragment fragment = (MyFragment) super.instantiateItem(container, position); mPageReferenceMap.put(position, fragment); return fragment; } 

我find了另外一种方法,不知道是否会有使用它的问题,对我来说似乎没问题。

我正在检查FragmentStatePageAdapter的代码,我看到了这个方法:

 @Override 52 public Object More ...instantiateItem(View container, int position) { 53 // If we already have this item instantiated, there is nothing 54 // to do. This can happen when we are restoring the entire pager 55 // from its saved state, where the fragment manager has already 56 // taken care of restoring the fragments we previously had instantiated. 57 if (mFragments.size() > position) { 58 Fragment f = mFragments.get(position); 59 if (f != null) { 60 return f; 61 } 62 } 63 64 if (mCurTransaction == null) { 65 mCurTransaction = mFragmentManager.beginTransaction(); 66 } 67 68 Fragment fragment = getItem(position); 69 if (DEBUG) Log.v(TAG, "Adding item #" + position + ": f=" + fragment); 70 if (mSavedState.size() > position) { 71 Fragment.SavedState fss = mSavedState.get(position); 72 if (fss != null) { 73 fragment.setInitialSavedState(fss); 74 } 75 } 76 while (mFragments.size() <= position) { 77 mFragments.add(null); 78 } 79 fragment.setMenuVisibility(false); 80 mFragments.set(position, fragment); 81 mCurTransaction.add(container.getId(), fragment); 82 83 return fragment; 84 } 

您可以使用此方法来获取已经为该特定位置安装的片段。 所以如果你想在第一个位置获得Fragment,你只需要调用:

 myFragmentStatePageAdpater.instantiateItem(null, 1) 

希望有所帮助

我通过向FragmentStatePagerAdapter添加一个getItemTag(int position)函数来实现这个function。 如果有其他人想要走这条路线,则更新文件的下载版本就在这里 。

在您的getItem()方法中将碎片存储到HashMap的解决scheme在您的活动被重新创build时不起作用!

问题是,FragmentStatePagerAdapter的默认实现直接从FragmentManager中恢复片段,而不调用getItem()方法。 这意味着你永远不会有机会存储你的片段的引用。

有关更多信息,请参阅源代码: FragmentStatePagerAdapter#restoreState 。

这基本上意味着获得对你的片段的引用的唯一方法是通过reflection。 这是相对 * 安全 **,如果你使用支持库。

就是这样:

  @SuppressWarnings("unchecked") public Fragment getFragment(int position) { try { Field f = FragmentStatePagerAdapter.class.getDeclaredField("mFragments"); f.setAccessible(true); ArrayList<Fragment> fragments = (ArrayList<Fragment>) f.get(this); if (fragments.size() > position) { return fragments.get(position); } return null; } catch (Exception e) { throw new RuntimeException(e); } } 

相对 *意味着它不像使用框架类的reflection那样危险。 支持类被编译到您的应用程序中,并且这些代码无法在您的设备上运行,但会在其他设备上崩溃。 通过将支持库更新到更新版本,您仍然可能会破坏此解决scheme

安全 **它从来没有真正安全的使用reflection; 但是当你使用的库存在devise缺陷时,你必须使用这种方法。

作为@Lancelot提到,你可以调用并将结果投到你的SuperCoolFragment:

 SuperCoolFragment frag = (SuperCoolFragment) yourFragmentStatePageAdpater.instantiateItem(null, position); 

我试图弗兰克的答案,build议第二种方法从它的教程链接,机器人由于某种原因添加方法getFragment()我的ViewPagerAdapter我无法通过mViewPager.getAdapter访问它。 getFragment ()就好像它不存在一样,所以我将mPageReferenceMap声明从ViewPagerAdapter移到了封闭类中,这样它就可以很容易地从封闭类的任何一点进行访问(在我的情况下,它是来自其他片断的MainActivity的callback方法),最后使得在片段之间传递数据成为可能。 感谢弗兰克,随时实施我的夹具,如果你喜欢我面临问题与访问自定义getFragment方法。

另一个解决scheme是复制粘贴FragmentStatePagerAdapter的源代码并添加一个getFragment方法:

 public Fragment getFragment(int position) { if (position >= mFragments.size()) { return null; } return mFragments.get(position); } 

重写setPrimaryItem ,并使用该位置,这将是正确的页面索引:

 @Override public void setPrimaryItem(ViewGroup container, int position, Object object) { super.setPrimaryItem(container,position,object); if (position == 1) { currentPageIndex=cameraFragment.pageIndex; } 

单行答案

这个简单的解决scheme对我来说很好。

YourFragment fragment =(YourFragment)getSupportFragmentManager()。getFragments()。get(0);

< – 如果您知道片段列表中的片段位置

创build一个拥有新的SuperCoolFragment对象的持有者。 然后标记并返回持有者对象。

 @Override public Fragment getItem(int position) { SuperCoolFragment superCoolFragment = new SuperCoolFragment(); superCoolFragment.setTag(YOUR_TAG); return superCoolFragment; }