当我启动应用程序时,一切正常,但当我旋转到横向时,它崩溃了,因为在Fragment
中有一个字段是 NULL
.
我不使用setRetainInstance(true)
或将 fragment 添加到 FragmentManager
我在应用程序启动和应用程序旋转时创建新的 fragment 。
在 Activity
OnCreate()
我创建 Fragment
并将它们添加到 viewPager
像这样。
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
ParentBasicInfoFragment parentBasicInfoFragment = new ParentBasicInfoFragment();
ParentUTCFragment parentUTCFragment = new ParentUTCFragment();
ParentEventsFragment parentEventsFragment = new ParentEventsFragment();
this.mFragments = new ArrayList<>();
this.mFragments.add(parentBasicInfoFragment);
this.mFragments.add(parentUTCFragment);
this.mFragments.add(parentEventsFragment);
this.viewpage.setOffscreenPageLimit(3);
setCurrentTab(0);
this.viewpage.setAdapter(new MainActivityPagerAdapter(getSupportFragmentManager(), this.mFragments));
}
然后我在应用程序上有一个测试按钮,当我按下它时,它会像
public void test(View view) {
((BaseFragment) MainActivity.this.mFragments.get(MainActivity.this.viewpage.
getCurrentItem())).activityNotifiDataChange("hello");
}
这将起作用并且当前的 Fragments
在 ViewPager
有方法,activityNotifiDataChange()
正在被调用,一切正常。
当我旋转应用程序并执行相同的操作时,按下按钮 activityNotifiDataChange()
正在被调用,但存在空指针异常,因为 ArrayList<Fragment> mFragment
现在为 NULL。
这是一个显示此行为的小型 Android Studio 项目示例: https://drive.google.com/file/d/1Swqu59HZNYFT5hMTqv3eNiT9NmakhNEb/view?usp=sharing
启动应用程序并按下名为“PRESS TEST”的按钮,然后旋转设备并再次按下按钮并观察应用程序崩溃
更新解决方案,感谢@GregMoens 和@EpicPandaForce
public class MainActivityPagerAdapter extends PersistenPagerAdapter<BaseFragment> {
private static int NUM_ITEMS = 3;
public MainActivityPagerAdapter(FragmentManager fm) {
super(fm);
}
public int getCount() {
return NUM_ITEMS;
}
@Override
public Fragment getItem(int position) {
switch (position) {
case 0:
return ParentBasicInfoFragment.newInstance(0, "Page # 1");
case 1:
return ParentUTCFragment.newInstance(1, "Page # 2");
case 2:
return ParentEventsFragment.newInstance(2, "Page # 3");
default:
return null;
}
}
}
public abstract class PersistenPagerAdapter<T extends BaseFragment> extends FragmentPagerAdapter {
private SparseArray<T> registeredFragments = new SparseArray<T>();
public PersistenPagerAdapter(FragmentManager fragmentManager) {
super(fragmentManager);
}
@Override
public T instantiateItem(ViewGroup container, int position) {
T fragment = (T)super.instantiateItem(container, position);
registeredFragments.put(position, fragment);
return fragment;
}
@Override
public void destroyItem(ViewGroup container, int position, Object object) {
registeredFragments.remove(position);
super.destroyItem(container, position, object);
}
public T getRegisteredFragment(ViewGroup container, int position) {
T existingInstance = registeredFragments.get(position);
if (existingInstance != null) {
return existingInstance;
} else {
return instantiateItem(container, position);
}
}
}
最佳答案
我在您的应用程序中看到的主要问题是您对 FragmentPagerAdapter 工作方式的误解。我经常看到这种情况,这是因为类(class)中缺乏好的 javadoc。应实现适配器,以便 getItem(position) 在调用时返回一个新的 fragment 实例。然后 getItem(position) 仅当寻呼机需要该位置的新实例时才会调用。您不应该预先创建 fragment 然后将其传递到适配器中。您也不应该对来自您的 Activity 或父 fragment (如 ParentBasicInfoFragment)的 fragment 持有强引用。因为请记住, fragment 管理器正在管理 fragment ,您也可以通过更新 fragment 并保留对它们的引用来管理 fragment 。这会导致冲突,并且在旋转后,您尝试在未实际初始化的 fragment 上调用 ActivityNotifiDataChange() (未调用 onCreate() )。使用调试器和跟踪对象 ID 将确认这一点。
如果您更改代码,以便 FragmentPagerAdapter 在需要时创建 fragment ,并且不存储对 fragment 或 fragment 列表的引用,您将看到更好的结果。
关于android - Android 中旋转设备后 Fragment 字段为 NULL,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53978606/