似乎很多查看此问题的人都在寻找一种方法来引用由FragmentPagerAdapter/FragmentStatePagerAdapter 创建的Fragments。我想提供我的解决方案,而不依赖 internally 创建的 tags,此处其他答案使用。
作为奖励,此方法也适用于FragmentStatePagerAdapter。有关详细信息,请参阅下面的注释。
当前解决方案的问题:依赖内部代码
我在这个问题和类似问题上看到的许多解决方案都依赖于通过调用FragmentManager.findFragmentByTag() 并模仿internally created tag: "android:switcher:" + viewId + ":" + id 来获取对现有Fragment 的引用。这样做的问题是您依赖于内部源代码,众所周知,不能保证永远保持不变。 Google 的 Android 工程师可以轻松决定更改 tag 结构,这会破坏您的代码,导致您无法找到对现有 Fragments 的引用。
不依赖内部tag 的替代解决方案
这是一个简单示例,说明如何获取对 FragmentPagerAdapter 返回的 Fragments 的引用,该引用不依赖于 Fragments 上设置的内部 tags。关键是覆盖instantiateItem() 并将引用保存在其中而不是在getItem() 中。
public class SomeActivity extends Activity {
private FragmentA m1stFragment;
private FragmentB m2ndFragment;
// other code in your Activity...
private class CustomPagerAdapter extends FragmentPagerAdapter {
// other code in your custom FragmentPagerAdapter...
public CustomPagerAdapter(FragmentManager fm) {
super(fm);
}
@Override
public Fragment getItem(int position) {
// Do NOT try to save references to the Fragments in getItem(),
// because getItem() is not always called. If the Fragment
// was already created then it will be retrieved from the FragmentManger
// and not here (i.e. getItem() won't be called again).
switch (position) {
case 0:
return new FragmentA();
case 1:
return new FragmentB();
default:
// This should never happen. Always account for each position above
return null;
}
}
// Here we can finally safely save a reference to the created
// Fragment, no matter where it came from (either getItem() or
// FragmentManger). Simply save the returned Fragment from
// super.instantiateItem() into an appropriate reference depending
// on the ViewPager position.
@Override
public Object instantiateItem(ViewGroup container, int position) {
Fragment createdFragment = (Fragment) super.instantiateItem(container, position);
// save the appropriate reference depending on position
switch (position) {
case 0:
m1stFragment = (FragmentA) createdFragment;
break;
case 1:
m2ndFragment = (FragmentB) createdFragment;
break;
}
return createdFragment;
}
}
public void someMethod() {
// do work on the referenced Fragments, but first check if they
// even exist yet, otherwise you'll get an NPE.
if (m1stFragment != null) {
// m1stFragment.doWork();
}
if (m2ndFragment != null) {
// m2ndFragment.doSomeWorkToo();
}
}
}
或如果您更喜欢使用tags 而不是类成员变量/对Fragments 的引用,您也可以以相同的方式获取FragmentPagerAdapter 设置的tags:
注意:这不适用于FragmentStatePagerAdapter,因为它在创建Fragments 时没有设置tags。
@Override
public Object instantiateItem(ViewGroup container, int position) {
Fragment createdFragment = (Fragment) super.instantiateItem(container, position);
// get the tags set by FragmentPagerAdapter
switch (position) {
case 0:
String firstTag = createdFragment.getTag();
break;
case 1:
String secondTag = createdFragment.getTag();
break;
}
// ... save the tags somewhere so you can reference them later
return createdFragment;
}
请注意,此方法不依赖于模仿FragmentPagerAdapter 设置的内部tag,而是使用适当的API 来检索它们。这样,即使 tag 在 SupportLibrary 的未来版本中发生更改,您仍然是安全的。
不要忘记,根据您的 Activity 的设计,您尝试使用的 Fragments 可能存在也可能不存在,因此您必须考虑到这一点在使用您的参考资料之前进行null 检查。
另外,如果您使用的是FragmentStatePagerAdapter,那么您不想保留对您的Fragments 的硬引用,因为您可能有很多硬引用,而硬引用将是不必要的将它们留在记忆中。而是将 Fragment 引用保存在 WeakReference 变量中,而不是标准变量中。像这样:
WeakReference<Fragment> m1stFragment = new WeakReference<Fragment>(createdFragment);
// ...and access them like so
Fragment firstFragment = m1stFragment.get();
if (firstFragment != null) {
// reference hasn't been cleared yet; do work...
}