Android FragmentStatePagerAdapter,如何标记片段以便稍后查找
使用Android FragmentStatePagerAdapter,如何标记片段以便稍后查找,android,android-viewpager,Android,Android Viewpager,使用FragmentStatePageAdapter时,我得到如下片段: @Override public Fragment getItem(int position) { return new SuperCoolFragment(); } public MyFragment getFragment(int key) { return mPageReferenceMap.get(key); } 然而,稍后在我的代码中,我需要找到这个片段来设置属
FragmentStatePageAdapter
时,我得到如下片段:
@Override
public Fragment getItem(int position) {
return new SuperCoolFragment();
}
public MyFragment getFragment(int key) {
return mPageReferenceMap.get(key);
}
然而,稍后在我的代码中,我需要找到这个片段来设置属性。在我使用片段的应用程序的一些其他部分中,我基本上会使用findFragmentByTag(tag)
标记它们并查找它们,但现在我不知道如何做
如何使用
FragmentStatePageAdapter
查找片段?创建一个固定器来固定新的SupercolFragment对象。然后标记并返回holder对象
@Override
public Fragment getItem(int position) {
SuperCoolFragment superCoolFragment = new SuperCoolFragment();
superCoolFragment.setTag(YOUR_TAG);
return superCoolFragment;
}
*编辑* 正如@ElliotM所指出的,有一个更好的解决方案。无需更改适配器中的任何内容,只需使用以下内容获取片段:
Fragment myFragment = (Fragment) adapter.instantiateItem(viewPager, viewPager.getCurrentItem());
*旧解决方案*
最佳选择是第二种解决方案:
简而言之:您可以跟踪所有“活动”片段页面。在本例中,您将跟踪FragmentStatePagerAdapter中的片段页面,该页面由ViewPager使用
public Fragment getItem(int index) {
Fragment myFragment = MyFragment.newInstance();
mPageReferenceMap.put(index, myFragment);
return myFragment;
}
为了避免保留对“非活动”片段页面的引用,我们需要实现FragmentStatePagerAdapter的destroyItem(…)方法:
。。。当您需要访问当前可见的页面时,您可以调用:
int index = mViewPager.getCurrentItem();
MyAdapter adapter = ((MyAdapter)mViewPager.getAdapter());
MyFragment fragment = adapter.getFragment(index);
。。。其中MyAdapter的getFragment(int)方法如下所示:
@Override
public Fragment getItem(int position) {
return new SuperCoolFragment();
}
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;
}
我通过向
FragmentStatePagerAdapter
添加一个getItemTag(int位置)
函数来实现这一点。如果其他人想使用此方法,则可以使用更新文件的插入版本。如果重新创建活动,则在getItem()方法中将片段存储到HashMap的解决方案不起作用强>
问题是,FragmentStatePagerAdapter的默认实现直接从FragmentManager恢复片段,而不调用getItem()方法。这意味着您永远不会有机会存储对片段的引用
有关更多信息,请参阅源代码:
这基本上意味着获得片段引用的唯一方法是借助反射。这是相对安全的**,以防您使用支持库
以下是方法:
@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);
}
}
@SuppressWarnings(“未选中”)
公共片段getFragment(int位置){
试一试{
字段f=FragmentStatePagerAdapter.class.getDeclaredField(“MFFragments”);
f、 setAccessible(true);
ArrayList片段=(ArrayList)f.get(this);
if(fragments.size()>位置){
返回碎片。获取(位置);
}
返回null;
}捕获(例外e){
抛出新的运行时异常(e);
}
}
相对而言*意味着它不像在框架类上使用反射那样危险。支持类被编译到你的应用程序中,这段代码不可能在你的设备上工作,但会在其他设备上崩溃。通过将支持库更新到新版本,您仍有可能破坏此解决方案
安全**使用反射永远不会真正安全;但是,当您使用的库存在设计缺陷时,您必须采用这种方法。我找到了另一种方法,不确定使用它是否会有任何问题,我觉得这样做没问题 我正在检查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 }
希望有帮助我尝试了Frank的答案,建议使用链接教程中的第二种方法,在将方法getFragment()添加到我的ViewPagerAdapter后,出于某种原因,我无法通过mViewPager.getAdapter访问它。getFragment(),好像它不存在一样,因此,我将mPageReferenceMap声明从ViewPagerAdapter移到了封闭类中,这样就可以从封闭类的任何一点轻松访问它(在我的例子中,它是MainActivity从其他片段的回调方法),这最终使在片段之间传递数据成为可能。
感谢Frank,如果您喜欢我在访问自定义getFragment方法时遇到问题,请随意实现我的fixture 另一种解决方案是复制粘贴的源代码并添加
getFragment
方法:
public Fragment getFragment(int position) {
if (position >= mFragments.size()) {
return null;
}
return mFragments.get(position);
}
正如@Lancelot所提到的,您可以调用并将结果投射到SupercolFragment:
SuperCoolFragment frag = (SuperCoolFragment) yourFragmentStatePageAdpater.instantiateItem(null, position);
覆盖
setPrimaryItem
,并使用该位置,它将是正确的页面索引:
@Override
public void setPrimaryItem(ViewGroup container, int position, Object object) {
super.setPrimaryItem(container,position,object);
if (position == 1) {
currentPageIndex=cameraFragment.pageIndex;
}
使用final FragmentManager fm=getActivity().getSupportFragmentManager()怎么样;最终Bundle args=新Bundle();fm.putFragment(args,TAG,this)并将此args包发送到新片段的新实例?我想知道如果进程被终止并重新启动,对片段的引用会发生什么。。。持久化args包中的引用仍然指向片段的正确实例吗?我最终使用LocalBroadcastManager来传递片段。你不应该简单地调用你的Adapter.getItem(position)吗?我已经讨论了所有这些以及其他一些答案,但是@2cupsOfTech,你的注释,是我的答案!打得好,链接中的第二个解决方案正是我需要的FragmentStatePagerAdapter。我刚刚开始熟悉ViewPager API,对如何跟踪感到困惑。这是最直截了当的思考方式。我也使用过类似的解决方案,希望链接有我以前没有做过的事情:(无论如何,这还不错,我只希望适配器能够提供一种机制来访问它内部使用的FragmentManager。如果主机活动被销毁并从头开始重新创建,这将不起作用。getItem(index)将不会被调用,您的mPageReferenceMap将为空。转到开发人员选项->“不要保留活动”你自己看看。我检查了我的代码,很早以前就退出了,但我认为添加了实例化项,请参见上面的编辑。也许这会解决你的问题?同意@Alexe吗