8

I've got a problem with my android app crashing when trying to restore my fragments. I have not added any custom variables to the bundle that I'm trying to restore, It's all default. I'm using Fragments and ViewPager. See my code snippets below:

public static class MyAdapter extends FragmentStatePagerAdapter {
    public MyAdapter(FragmentManager fm) {
        super(fm);
    }

    @Override
    public int getCount() {
        return NUM_ITEMS;
    }

    public int getCurrentItemPosition(Fragment fragment){
        return getItemPosition(fragment);
    }

    @Override
    public Fragment getItem(int position) {
        return ContentFragment.newInstance(position);
    }
}

public class MyActivity extends FragmentActivity {

static final int NUM_ITEMS = 100000;
public int currentSelectedPage;
private int changeToFragmentIndex;
public DateTime midDate;
MyAdapter mAdapter;
ViewPager mPager;

/** Called when the activity is first created. */
@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.diary);
    MyApplication application = (MyApplication)getApplication();
    application.dataController.myActivity = this;
    mAdapter = new MyAdapter(getSupportFragmentManager());
    mPager = (ViewPager)findViewById(R.id.pager);
    mPager.setAdapter(mAdapter);
    int newDay = application.daysBetween(DateTime.now(), DateTime.parse(application.day.dateToShortString()));

    this.currentSelectedPage = NUM_ITEMS/2+newDay;
    mPager.setCurrentItem(NUM_ITEMS/2+newDay);
    mPager.setOnPageChangeListener(new SimpleOnPageChangeListener(){
        public void onPageSelected(int position){
            currentSelectedPage = position;
            ContentFragment fragment = (ContentFragment) mAdapter.instantiateItem(mPager, currentSelectedPage);
            fragment.loadData();
        }
    });
}

}

public class ContentFragment extends Fragment {
private View v;
static final int NUM_ITEMS = 100000;

static ContentFragment newInstance(int num) {
    ContentFragment f = new ContentFragment();

    return f;
}

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
        Bundle savedInstanceState) {
    if (container == null)
        return null;
    v = inflater.inflate(R.layout.diarycontent, container, false);
    return v;
}

@Override
public void onActivityCreated(Bundle savedInstanceState) {
    super.onActivityCreated(savedInstanceState);

}

@Override
public void onSaveInstanceState(Bundle savedInstanceState){
    super.onSaveInstanceState(savedInstanceState);
    setUserVisibleHint(true);
}
}

I receive this stackstrace:

Caused by: java.lang.NullPointerException
at android.support.v4.app.FragmentManagerImpl.getFragment(FragmentManager.java:519)
at android.support.v4.app.FragmentStatePagerAdapter.restoreState(FragmentStatePagerAdapter.java:1 55)
at android.support.v4.view.ViewPager.onRestoreInstanceState(ViewPager.java:522)

As I have understood this may be a known problem with the support package and that one possible solution would be to use setUserVisibleHint(true) in onSaveInstanceState. But that didn't help.

Does anyone know another solution to the problem or what I've done wrong?

4

3 回答 3

25

一旦我开始在 Tab 中使用 ViewPager 和 FragmentStatePagerAdapter,我就遇到了同样类型的问题。

然后我在所有与这个问题相关的论坛上玩了两天,想知道为什么会发生这个问题以及如何解决它,但没有找到任何符合我要求的完美解决方案。

我得到了解决方案,因为为了避免 NPE 崩溃使用 FragmentPagerAdapter 而不是 FragmentStatePagerAdapter。当我替换 FragmentPagerAdapter 而不是 FragmentStatePagerAdapter 时,不会遇到 NPE 崩溃问题,但同一页面不会自行刷新以进行进一步导航(这是我的要求)。

最后覆盖 FragmentStatePagerAdapter 上的 saveState 方法,一切正常。

@Override
public Parcelable saveState() {
    // Do Nothing
    return null;
}


我如何轻松重现此问题:
我使用的是更高版本(4.1)的设备并按照以下步骤操作:
1. 转到设置 -> 开发人员选项。
2. 单击“不保留活动”选项。

现在我玩了我的应用程序。

在每次应用程序由于 android.support.v4.app.FragmentManagerImpl.getFragment(Unknown Source) 处的 NPE 而崩溃时覆盖 saveState() 方法之前。但是在覆盖 saveState() 之后没有注册崩溃。

我希望这样做你不会有任何问题。

于 2013-03-16T02:32:30.320 回答
2

我最初使用@Lalit Kumar Sahoo 建议的解决方案。但是,我注意到一个严重的问题:每次旋转设备时,片段管理器都会添加新片段,而不会删除旧片段。所以我进一步搜索,发现了一个带有解决方法建议的错误报告(帖子#1)。我使用了此修复程序并使用我的应用程序进行了测试,该问题似乎已解决,没有任何副作用:

解决方法:在项目的 src/android/support/v4/app 文件夹中创建自定义 FragmentStatePagerAdapter 并使用它。

package android.support.v4.app;

import android.os.Bundle;
import android.view.ViewGroup;

public abstract class FixedFragmentStatePagerAdapter extends FragmentStatePagerAdapter {

  public FixedFragmentStatePagerAdapter(FragmentManager fm) {
    super(fm);
  }

  @Override
  public Object instantiateItem(ViewGroup container, int position) {
    Fragment f = (Fragment)super.instantiateItem(container, position);
    Bundle savedFragmentState = f.mSavedFragmentState;
    if (savedFragmentState != null) {
      savedFragmentState.setClassLoader(f.getClass().getClassLoader());
    }
    return f;
  }
}
于 2013-10-15T09:13:07.483 回答
-1

你究竟为什么要这样做:

mPager.setOnPageChangeListener(new SimpleOnPageChangeListener(){
    public void onPageSelected(int position){
        currentSelectedPage = position;
        ContentFragment fragment = (ContentFragment) mAdapter.instantiateItem(mPager, currentSelectedPage);
        fragment.loadData();
    }
});

这个:

@Override
public Fragment getItem(int position) {
    return ContentFragment.newInstance(position);
}

实例化片段。

您可以在片段中加载这样的数据:

@Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
loadData();
}
于 2012-06-19T20:38:06.917 回答