【发布时间】:2019-10-29 18:13:25
【问题描述】:
当我启动应用程序时一切正常,但是当我旋转到横向时它崩溃了,因为在 Fragment 中有一个字段是 NULL。
我不使用setRetainInstance(true) 或将片段添加到FragmentManager我在应用启动和应用旋转时创建新片段。
在ActivityOnCreate() 中,我创建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");
}
这将起作用,并且ViewPager 中的当前Fragments 具有正在调用的方法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);
}
}
}
【问题讨论】:
-
这是因为当方向改变时,片段会从头开始重新创建。如果您想重新获得变量的值,您需要使用您提到的 setInstantState(true) 或上下文来设置引用。请参阅此链接以供参考link
-
我知道它们是重新创建的,这就是为什么我在
FragmentonViewCreated()中设置该字段,但旋转后该字段仍然为空 -
只在
if(savedInstanceState == null)... 时操作视图,否则代码再次运行。特别是setCurrentTab(0);打破了旋转屏幕并仍然期望看到相同标签的想法(savedInstanceState也可用于记住实际的当前标签)。 -
this.mFragments = new ArrayList<>();因为这是错误的。你永远不应该持有对片段列表的引用。只需从FragmentAdapter的getItem(int position)返回 Fragment 的新实例,您就可以开始了