java.lang.IllegalStateException:键f1:index 3不再存在片段

时间:2012-08-01 09:12:33

标签: android android-fragments

我想了解这个异常,以便实现正确的修复。

有一个ViewPager,它使用FragmentStatePagerAdapter通过getItem和MyFragmentClass.newInstance(...)实例化2个片段。

Adapter的getItem看起来像这样:

@Override
public Fragment getItem(int position) {
    Fragment fragment = null;

    switch(position) {
        case 0:
            fragment = MyFragment2.newInstance(par1);
            break;
        case 1:
            fragment = MyFragment2.newInstance(par2, par3);
            break;
    }
    return fragment;
}

问题:

当活动被销毁并再次创建时,适配器再次被实例化,片段再次使用MyFragmentClass.newInstance(...)创建...但是在此行上:

pager.setAdapter(adapter);

我得到了上述例外情况。

我查看了抛出异常的源代码,就是这样:

@Override
public Fragment getFragment(Bundle bundle, String key) {
    int index = bundle.getInt(key, -1);
    if (index == -1) {
        return null;
    }
    if (index >= mActive.size()) {
        throw new IllegalStateException("Fragement no longer exists for key "
                + key + ": index " + index);
    }
    Fragment f = mActive.get(index);
    if (f == null) {
        throw new IllegalStateException("Fragement no longer exists for key "
                + key + ": index " + index);
    }
    return f;
}

所以在那里传递一个bundle,其中一些状态引用了我的旧片段,但这与当前状态(mActive)不对应,并抛出了异常。

我不明白这背后的想法是什么,或者我应该以哪种方式实例化片段。

我尝试了从另一个环境获得的技巧:

pager.setOffscreenPageLimit(1);

为了避免片段在屏幕外被破坏(在2页viewpager的情况下,虽然不知道它是否适用于状态适配器)。但似乎没有关联,至少,它没有帮助,仍然得到相同的例外。

捕获异常导致页面空白。

8 个答案:

答案 0 :(得分:51)

这可能会有所帮助 -

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

FragmentStatePagerAdapter

中添加上面一行

答案 1 :(得分:20)

如果你不希望片段在屏幕外被回收,你应该使用FragmentPagerAdapter而不是FragmentStatePagerAdapter

答案 2 :(得分:8)

如果您使用的是ViewPager2,则对ViewPager2对象使用此方法

viewPager2.setSaveEnabled(false);

答案 3 :(得分:3)

我整天都在努力解决这个问题,但现在我找到了解决办法。

private ViewPager _mViewPager;
_mViewPager.setOffscreenPageLimit(5);
//5 is how much page you have.

setOffscreenPageLimit设置在空闲状态下应保留到视图层次结构中当前页面任一侧的页数。超出此限制的页面将在需要时从适配器重新创建。

答案 4 :(得分:3)

问题详细信息

     默认情况下,FragmentStatePagerAdapter将保存和恢复ViewPager的状态。在恢复时,如果片段实例由于某种原因被杀死,则FragmentManger将抛出此异常。

解决方案:

要解决此问题,需要覆盖我们的FragmentStatePagerAdapter中的restoreState方法,并尝试try catch块。它将防止崩溃,并且在正常情况下还将保留viewpager的片段状态。

@Override
public void restoreState(Parcelable state, ClassLoader loader) {
    try {
        super.restoreState(state, loader);
    } catch (Exception e) {
        Log.e("TAG", "Error Restore State of Fragment : " + e.getMessage(), e);
    }
}

注意:我们可以使用FragmentPagerAdapter或Override saveState()并返回null也可以解决此问题,但在正常情况下viewpager不会保留其状态。

答案 5 :(得分:1)

非常好!由于在调用pager.setAdapter(adapter);导致异常时重复restoreState

Fragment no longer exists for key f0: index 0

我们可以发布片段RootView

    public void onDestroyView() {
    super.onDestroyView();
    if (isRecyclerRootViewAlways()) {
        mRootView = null;//<--
    }
    mMyFragmentLifecycle.onFragmentDestroyView(this);
}

答案 6 :(得分:0)

使用Activity lifeCycle代替Fragment。

public class MyAdapter extends FragmentStateAdapter {

    public MyAdapter (@NonNull Fragment fragment) {
        super(fragment.getFragmentManager(), fragment.getActivity().getLifecycle());
    }
}

或者像其他提到的那样禁用ViewPager2保存状态。

  • 在布局中:android:saveEnabled="false"
  • 在代码中:
    • viewPager.setSaveEnabled(false);
    • viewPager.setSaveFromParentEnabled(false);

答案 7 :(得分:-3)

使用

  

getFragmentManager()

片段适配器中的

不是儿童片段管理员

PagerAdapter adapter = new PagerAdapter(getFragmentManager());

我希望这会有所帮助。