android-fragments java.lang.IllegalStateException:键f1的片段不再存在:索引3

ttvkxqim  于 2022-11-13  发布在  Android
关注(0)|答案(9)|浏览(250)

我想了解此异常,以便实现正确的修复。
有一个ViewPager,它使用一个FragmentStatePagerAdapter通过getItem和MyFragmentClass.newInstance(...)示例化2个片段。
适配器的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;
}

问题:
当Activity被销毁并再次创建时,适配器将再次被intantiated,片段将再次使用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的情况下,虽然不知道它是否与state adapter一起工作得很好)。但似乎没有相关性,至少,它没有帮助,仍然得到相同的异常。
捕获异常会导致页面为空。

eivgtgni

eivgtgni1#

这可能会有帮助-

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

将上面的行添加到FragmentStatePagerAdapter中。

2guxujil

2guxujil2#

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

pbpqsu0x

pbpqsu0x3#

问题详细信息

默认情况下,FragmentStatePagerAdapter将保存并恢复ViewPager的状态。在恢复时,如果片段示例由于某种原因而被终止,则FragmentManger将引发此异常。

解决方案:

要修复此问题,需要覆盖FragmentStatePagerAdapter中的restoreState方法并放置try catch块。这将防止崩溃,并在正常情况下保留视图页的片段状态。

@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不会保留其正常情况下得状态.

jljoyd4f

jljoyd4f4#

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

viewPager2.setSaveEnabled(false);
iyfjxgzm

iyfjxgzm5#

我在这个问题上纠结了一整天,但现在我找到了解决办法。

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

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

deyfvvtc

deyfvvtc6#

使用 活动 生命 周期 而 不是 片段 。

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

toe950277#

很好!由于是重复pager.setAdapter(adapter);,当调用restoreState时会引起异常:

Fragment no longer exists for key f0: index 0

我们可以释放根视图片段

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

toe950278#

viewpager2与recyclerview https://issuetracker.google.com/issues/154751401分离时出现问题
据我所知,有两种修复方法:
1.在xml viewpager2组件中添加此行。

android:saveEnabled="false"

但是上面的一个不保存当前示例,片段每次弹出时都会重新创建。
1.建议的解决方案是在您的片段上添加以下行

override fun onDestroyView() {
   super.onDestroyView()
   viewPager.adapter = null
}
ujv3wf0j

ujv3wf0j9#

用途
获取片段管理器()
在片段适配器中,而不是在子片段管理器中

PagerAdapter adapter = new PagerAdapter(getFragmentManager());

我希望这能帮上忙。

相关问题