在Android中旋转设备后,Fragment字段为NULL [英] Fragment Field is NULL after rotate device in Android

查看:69
本文介绍了在Android中旋转设备后,Fragment字段为NULL的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

当我启动该应用程序时,一切正常,但是当我旋转以横向显示时,它崩溃了,因为在Fragment中有一个字段为NULL.

When I start the app everything works ok but when I rotate to landscape it crashes because in the Fragment there is a field that is NULL.

我不使用setRetainInstance(true)或将片段添加到FragmentManager,我在应用程序启动时和应用程序旋转时创建新的片段.

I dont use setRetainInstance(true) or adding Fragments to FragmentManagerI create new Fragments on app start and when app rotate.

Activity OnCreate()中,我创建Fragment并将其添加到viewPager中,如下所示.

In the Activity OnCreate() I create the Fragment and adding them to the viewPager like this.

   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));
    }

然后我在应用程序上有一个测试按钮,当我按该按钮时,它会像

Then I have a test button on the app that when I press it will do like

  public void test(View view) {
      ((BaseFragment) MainActivity.this.mFragments.get(MainActivity.this.viewpage.
                getCurrentItem())).activityNotifiDataChange("hello");
  }

这将起作用,并且ViewPager中的当前Fragments具有被调用的方法activityNotifiDataChange(),并且一切正常.

This will work and the current Fragments in the ViewPager have the method, activityNotifiDataChange() that are being called and all is ok.

当我旋转应用程序并按按钮执行相同的操作时,activityNotifiDataChange()被称为正常,但由于ArrayList<Fragment> mFragment现在为NULL,所以出现了空指针异常.

When I rotate the app and do the same thing pressing the button the activityNotifiDataChange() is being called alright but there a null pointer exception because the ArrayList<Fragment> mFragment is now NULL.

这是一个小示例Android Studio项目,显示了以下行为: https://drive.google.com/file/d/1Swqu59HZNYFT5hMTqv3eNiT9NmakhNEb/view?usp = sharing

Here´s a small sample Android Studio project showing this behavior: https://drive.google.com/file/d/1Swqu59HZNYFT5hMTqv3eNiT9NmakhNEb/view?usp=sharing

启动应用程序并按下名为"PRESS TEST"的按钮,然后旋转设备并再次按下按钮,以查看应用程序崩溃

Start app and press button named "PRESS TEST", then rotate device and press the button again and watch the app crash

更新解决方案,感谢@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的工作方式有误解.我经常看到这种情况,这是由于该类缺少良好的javadocs.应该实现适配器,以便在调用getItem(position)时返回一个新的片段实例.然后,只有在该页面需要一个新实例时,该寻呼机才会调用getItem(position).您不应该预先创建片段,然后将其传递到适配器中.您也不应持有对活动或父片段(如ParentBasicInfoFragment)中的片段的强引用.因为请记住,片段管理器正在管理片段,因此您还通过更新片段并保留对其的引用来管理片段.这会导致冲突,并且轮换后,您尝试在未实际初始化(未调用onCreate())的片段上调用activityNotifiDataChange().使用调试器和跟踪对象ID可以确认这一点.

The main problem I see with your app is your misunderstanding with how FragmentPagerAdapter works. I see this a lot and it's due to lack of good javadocs on the class. The adapter should be implemented so that getItem(position) returns a new fragment instance when called. And then getItem(position) will only be called by the pager when it needs a new instance for that position. You should not pre-create the fragments and pass then into the adapter. You should also not be holding strong references to the fragments from either your activity or from parent fragments (like ParentBasicInfoFragment). Because remember, the fragment manager is managing fragments and you are also managing fragments by newing them and keeping references to them. This is causing a conflict and after rotation, you are trying to invoke activityNotifiDataChange() on a fragment that is not actually initialized (onCreate() was not called). Using the debugger and tracking object IDs will confirm this.

如果您更改代码,以便FragmentPagerAdapter在需要时创建片段,并且不存储对片段或片段列表的引用,您会看到更好的结果.

If you change your code so that the FragmentPagerAdapter creates the fragments when they are needed and don't store references to fragments or lists of fragments, you will see much better results.

这篇关于在Android中旋转设备后,Fragment字段为NULL的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆