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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/11756102/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-20 08:44:32  来源:igfitidea点击:

java.lang.IllegalStateException: Fragment no longer exists for key f1: index 3

androidandroid-fragments

提问by Ixx

I want to understand this exception in order to implement a proper fix.

我想了解此异常以实施适当的修复。

There's a ViewPager and it uses a FragmentStatePagerAdapter to instantiate 2 fragments via getItem and MyFragmentClass.newInstance(...).

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

Adapter's getItem looks like this:

适配器的 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;
}

Problem:

问题:

When the activity is destroyed, and created again, the adapter is intantiated again, the fragments created again with MyFragmentClass.newInstance(...)... but then on this line:

当活动被销毁并再次创建时,适配器再次被初始化,片段再次使用MyFragmentClass.newInstance(...)...创建,但随后在这一行:

pager.setAdapter(adapter);

pager.setAdapter(adapter);

I get the mentioned exception.

我得到了提到的例外。

I looked in the source where the exception is thrown, it's this:

我查看了引发异常的源代码,是这样的:

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

So a bundle is passed there, with some state which references my old fragments, but this doesn't correspond to the current state (mActive), and the exception is thrown.

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

I don't understand what's the idea behind this, or which way I'm supposed to instantiate the fragments.

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

I tried a trick I got from another context:

我尝试了一个从另一个上下文中得到的技巧:

pager.setOffscreenPageLimit(1);

pager.setOffscreenPageLimit(1);

In order to avoid that the fragments are destroyed when they are off screen (in the case of 2 pages viewpager, although don't know if it works well with state adapter). But don't seems to be related, at least, it doesn't help, still get the same exception.

为了避免碎片在屏幕外时被破坏(在2页viewpager的情况下,虽然不知道它是否与状态适配器配合良好)。但似乎不相关,至少,它没有帮助,仍然得到相同的异常。

Catching the exception leads to the pages being blank.

捕获异常会导致页面空白。

回答by Mikelis Kaneps

This could help -

这可以帮助 -

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

Add the line above in FragmentStatePagerAdapter.

FragmentStatePagerAdapter.

回答by tad

If you don't want the fragments to get reclaimed when they are offscreen, you should be using FragmentPagerAdapterand not FragmentStatePagerAdapter.

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

回答by Vicky

Issue Detail

By default FragmentStatePagerAdapter will save and restore the state of ViewPager. While restore if fragment instance killed due to some reason then FragmentManger will throw this exception.

Solution:

To Fix this need to override the restoreState method in our FragmentStatePagerAdapter and put try catch block. It will prevent the crash and also it will retain the viewpager's fragment state for normal case.

问题详细信息

默认情况下,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);
    }
}

Note:We can use FragmentPagerAdapter or Override saveState() and return null also fix this issue but viewpager will not retain its state for the normal case.

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

回答by nabeel

if you are using ViewPager2 then use this method on ViewPager2 object

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

viewPager2.setSaveEnabled(false);

回答by Yi Wang

I have struggle on this problem for whole day, but now I found the solution.

我在这个问题上挣扎了一整天,但现在我找到了解决方案。

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

setOffscreenPageLimitSet the number of pages that should be retained to either side of the current page in the view hierarchy in an idle state. Pages beyond this limit will be recreated from the adapter when needed.

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

回答by u7062531

very good ! Since is repeat pager.setAdapter(adapter);when call restoreStatecause exception:

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

Fragment no longer exists for key f0: index 0

we can Release Fragment RootView

我们可以释放 Fragment RootView

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

回答by Amit Kumar

Use

getFragmentManager()

getFragmentManager()

in fragment adapter not child fragment manager

在片段适配器中不是子片段管理器

PagerAdapter adapter = new PagerAdapter(getFragmentManager());

I hope this helps.

我希望这有帮助。