问题总结
注意:在这个答案中,我将参考FragmentPagerAdapter
它的源代码。但一般的解决方案也应该适用于FragmentStatePagerAdapter
.
如果您正在阅读本文,您可能已经知道FragmentPagerAdapter
/FragmentStatePagerAdapter
是Fragments
为您创建的ViewPager
,但是在 Activity 重新创建时(无论是从设备旋转还是系统杀死您的应用程序以重新获得内存)这些Fragments
都不会再次创建,而是它们的从FragmentManager
. 现在说你Activity
需要参考这些Fragments
来做他们的工作。您没有id
ortag
为这些创建Fragments
,因为FragmentPagerAdapter
在内部设置它们。所以问题是如何在没有这些信息的情况下获得对它们的引用......
当前解决方案的问题:依赖内部代码
我在这个问题和类似问题上看到的很多解决方案都依赖于Fragment
通过调用FragmentManager.findFragmentByTag()
和模仿内部创建的标签来获取对现有标签的引用:"android:switcher:" + viewId + ":" + id
. 这样做的问题是您依赖于内部源代码,众所周知,不能保证永远保持不变。Google 的 Android 工程师可以轻松决定更改tag
结构,这会破坏您的代码,使您无法找到对现有Fragments
.
不依赖内部的替代解决方案tag
这是一个简单示例,说明如何获取对不依赖Fragments
于. 关键是在其中覆盖和保存引用而不是在.FragmentPagerAdapter
tags
Fragments
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
您也可以以相同的方式获取tags
集合FragmentPagerAdapter
:注意:这不适用,FragmentStatePagerAdapter
因为它tags
在创建Fragments
.
@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;
}
请注意,此方法不依赖于模仿内部tag
集合FragmentPagerAdapter
,而是使用适当的 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...
}