android - Android 中旋转设备后 Fragment 字段为 NULL

标签 android android-fragments

当我启动应用程序时,一切正常,但当我旋转到横向时,它崩溃了,因为在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");
  }

这将起作用并且当前的 FragmentsViewPager有方法,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/

相关文章:

java - 定义多个按钮

android - Firebase/Crashlytics 仪表板未显示任何 Android 测试崩溃

android - isValidFragment Android API 19

android - ViewPager 上未触发 OnLongClickListener

java - 当父级不是 Activity 而是 Fragment 时,选项卡为空

android - 从谷歌地图转换为开放街道 map (osmdroid)

java - 目标相当于 base16().decode(String)

java - Android 上的谷歌地图 Activity

android - 仅在父 fragment 中的操作栏中显示搜索 View

android - DialogFragment在Android中的位置