java.lang.IllegalStateException:键 f0 的片段不再存在:索引 1

Posted

技术标签:

【中文标题】java.lang.IllegalStateException:键 f0 的片段不再存在:索引 1【英文标题】:java.lang.IllegalStateException: Fragment no longer exists for key f0: index 1 【发布时间】:2018-01-25 20:17:14 【问题描述】:

我在一个 Activity 中有几个片段。完成一些过程后,我将使用以下代码关闭片段。

if (getActivity().getSupportFragmentManager().getBackStackEntryCount() > 0) 
                        getActivity().getSupportFragmentManager().popBackStackImmediate();

但是在 popBackStackImmediate() 线上它会抛出错误

    Process: com.TestProject.testpro, PID: 17966
 java.lang.IllegalStateException: Fragment no longer exists for key f0: index 1
     at android.support.v4.app.FragmentManagerImpl.getFragment(FragmentManager.java:879)
     at android.support.v4.app.FragmentStatePagerAdapter.restoreState(FragmentStatePagerAdapter.java:215)
     at android.support.v4.view.ViewPager.onRestoreInstanceState(ViewPager.java:1481)
     at android.view.View.dispatchRestoreInstanceState(View.java:14746)
     at android.view.ViewGroup.dispatchRestoreInstanceState(ViewGroup.java:3121)
     at android.view.ViewGroup.dispatchRestoreInstanceState(ViewGroup.java:3127)
     at android.view.ViewGroup.dispatchRestoreInstanceState(ViewGroup.java:3127)
     at android.view.View.restoreHierarchyState(View.java:14724)
     at android.support.v4.app.Fragment.restoreViewState(Fragment.java:475)
     at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:1329)
     at android.support.v4.app.FragmentManagerImpl.moveFragmentToExpectedState(FragmentManager.java:1528)
     at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:1595)
     at android.support.v4.app.BackStackRecord.executePopOps(BackStackRecord.java:807)
     at android.support.v4.app.FragmentManagerImpl.executeOps(FragmentManager.java:2360)
     at android.support.v4.app.FragmentManagerImpl.executeOpsTogether(FragmentManager.java:2149)
     at android.support.v4.app.FragmentManagerImpl.optimizeAndExecuteOps(FragmentManager.java:2103)
     at android.support.v4.app.FragmentManagerImpl.popBackStackImmediate(FragmentManager.java:823)
     at android.support.v4.app.FragmentManagerImpl.popBackStackImmediate(FragmentManager.java:776)
     at com.TestProject.testpro.application.fragments.WFMUpgradeToAffinityFragmentAN$WFMStoreProfileIdReceiver.onReceive(WFMUpgradeToAffinityFragmentAN.java:1064)
     at android.support.v4.content.LocalBroadcastManager.executePendingBroadcasts(LocalBroadcastManager.java:297)
     at android.support.v4.content.LocalBroadcastManager.access$000(LocalBroadcastManager.java:46)
     at android.support.v4.content.LocalBroadcastManager$1.handleMessage(LocalBroadcastManager.java:116)
     at android.os.Handler.dispatchMessage(Handler.java:102)
     at android.os.Looper.loop(Looper.java:148)
     at android.app.ActivityThread.main(ActivityThread.java:5417)
     at java.lang.reflect.Method.invoke(Native Method)
     at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:726)
     at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:616)

没有其他关闭片段的崩溃。我找不到这个问题的确切解决方案。请帮我解决这个问题。

编辑:

我正在使用下面的函数来调用片段。

void showContentFragment(Fragment newFragment, String backStackName) 
    //Log.e(TAG, "showContentFragment- " + "BackstackName: "+ backStackName);
    FragmentManager mFragmentManager = getActivity().getSupportFragmentManager();
    if (newFragment != null) 
        //updateNavigation(backStackName);
        FragmentTransaction ft = mFragmentManager.beginTransaction();
        ft.replace(R.id.fragment_container, newFragment);
        if (backStackName != null && !backStackName.isEmpty()) 
            ft.addToBackStack(backStackName);
        

        ft.commit();
    

【问题讨论】:

你试过只使用popBackStack() 吗? @Kiya 是的,我试过了。还是没有运气。 您是否将片段添加到后台堆栈?请在您在活动中添加片段的位置发布您的代码。 为什么需要手动执行此操作? getActivity().onBackPressed() 应该足以返回到上一个片段,以防你做得正确。 @Sniper 你解决了这个问题吗? 【参考方案1】:

对于 ViewPager2,只需使用 viewPager.setSaveEnabled(false);

【讨论】:

是的,它有效,我认为它来自***.com/questions/59486504/…。【参考方案2】:

在 ViewPager 适配器中,覆盖 restoreState(state, loader)

    @Override
    public void restoreState(final Parcelable state, final ClassLoader loader) 
        try 
            super.restoreState(state, loader);
         catch (Exception e) 
            e.printStackTrace();
        
    

【讨论】:

很遗憾,这不适用于 ViewPager2。 restoreState 被声明为 final。【参考方案3】:

请按照以下步骤从您的活动中添加片段

 getSupportFragmentManager().beginTransaction()
                .replace(R.id.frame, yourFragment, yourFragment.class.getSimpleName()).addToBackStack(yourFragment.class.getSimpleName())
                .commit();

使用此代码从您的片段中调用popBackStack()

    if (getFragmentManager().getBackStackEntryCount() > 0) 
                        getFragmentManager().popBackStack();

确保您正在导入正确的片段类

import android.support.v4.app.Fragment;

【讨论】:

我遵循上述相同的步骤。仍然面临这个问题。【参考方案4】:

在您的 Fragment 类中添加下面的代码,根据doc,它返回用于在 Fragment 准备关闭时将视图移出场景的转换。

@Override
    public Object getReturnTransition() 
        return super.getReturnTransition();
    

【讨论】:

也添加了这个。它仍然崩溃。 是的。同样的崩溃。【参考方案5】:

您的堆栈跟踪显示您正在使用ViewPager 并自己操作后台堆栈。

这可能不是一个好主意——要么让你的ViewPager 管理后台堆栈(它做得很好),要么完全自己管理。

请注意,在自己管理后台堆栈时,您必须考虑恢复实例状态(堆栈跟踪中的功能)和Fragment lifecycle。

这意味着在内存不足的情况下,您的 Activity 和 Fragments 将停止。如果您没有正确保存实例状态,当它们重新启动时,您将收到类似上述错误。如果您的 Fragments 的工作流程很简单,您可以使用 ViewPager 来避免所有这些。

【讨论】:

【参考方案6】:
public void showContentFragment(Fragment fragment, Bundle bundle, boolean addToBackStack) 
        if (bundle != null)
            fragment.setArguments(bundle);

        tag = fragment.getClass().getSimpleName();
        FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
        ft.setCustomAnimations(R.anim.slide_in_right, R.anim.slide_out_left, R.anim.slide_in_left, R.anim.slide_out_right);
        ft.replace(R.id.container_internal, fragment, tag);
        fragment.setRetainInstance(true); // IMPORTANT

        if (addToBackStack)
            ft.addToBackStack(tag);

        try 
            ft.commit();

         catch (Exception ex) 
            ex.printStackTrace();
            ft.commitAllowingStateLoss();
        

【讨论】:

【参考方案7】:

首先,您无需致电getActivity().getSupportFragmentManager()getFragmentManager() 足以拨打FragmentManager

如果您在 Support Fragment 中,getFragmentManager() 会给您supportFragmentManager() 或者它会给您app.Fragment Manager

如果您在 ViewPager 中调用 PopBackstack,它将不起作用。如果您在另一个片段中使用viewPager。你应该只在父片段中调用popBackstack。不在viewPager

试试下面的代码,它会根据返回的堆栈名称清除堆栈。

getFragmentManager.popBackStackImmediate(YourBackStackName, FragmentManager.POP_BACK_STACK_INCLUSIVE)

文档:https://developer.android.com/reference/android/app/FragmentManager.html#popBackStackImmediate(java.lang.String, int)

希望对你有帮助:)

【讨论】:

【参考方案8】:

在我的 viewPager 中覆盖 restoreState 方法对我有用。

override fun restoreState(state: Parcelable?, loader: ClassLoader?) 
        try 
            super.restoreState(state, loader)
         catch (e: Exception) 
            e.printStackTrace()
        
    

这是我的视图寻呼机的最终代码

class MenuTabAdapter(fm: FragmentManager) : FragmentStatePagerAdapter(fm) 
    private val mFragmentList = ArrayList<Fragment>()
    private val mFragmentTitleList = ArrayList<String>()
    private var mCurrentPosition = -1
    override fun getItem(position: Int): Fragment 
        return mFragmentList[position]
    

    override fun getCount(): Int 
        return mFragmentList.size
    

    fun addFragment(fragment: Fragment, title: String) 
        mFragmentList.add(fragment)
        mFragmentTitleList.add(title)
    

    override fun getPageTitle(position: Int): CharSequence? 
        return mFragmentTitleList[position]
    

    override fun setPrimaryItem(container: ViewGroup, position: Int, `object`: Any) 
        super.setPrimaryItem(container, position, `object`)


        if (position !== mCurrentPosition && container is HeightWrappingViewPager) 
            val fragment = `object` as Fragment
            if (fragment?.view != null) 
                mCurrentPosition = position
                container.requestLayout()
            
        
    

    override fun restoreState(state: Parcelable?, loader: ClassLoader?) 
        try 
            super.restoreState(state, loader)
         catch (e: Exception) 
            e.printStackTrace()
        
    

【讨论】:

【参考方案9】:

这个崩溃什么时候发生?

当ViewPager包裹Fragment时,Fragment内部有ViewPager包裹Fragment。 当外层Fragment或内层Adapter继承FragmentStatePagerAdapter,或两者都继承FragmentStatePagerAdapter时。

如何修复?

在报错的Fragment的Adapter中重写如下方法,返回null。

@Override  
public Parcelable saveState()   
    return null;  

更多详情here.

【讨论】:

以上是关于java.lang.IllegalStateException:键 f0 的片段不再存在:索引 1的主要内容,如果未能解决你的问题,请参考以下文章