【问题标题】:java.lang.IllegalStateException: Fragment no longer exists for key f0: index 1java.lang.IllegalStateException:键 f0 的片段不再存在:索引 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 你解决了这个问题吗?

标签: android android-fragments


【解决方案1】:

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

【讨论】:

【解决方案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.

          【讨论】:

            猜你喜欢
            • 2020-07-22
            • 2012-07-30
            • 2020-04-16
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2018-03-25
            • 2018-05-03
            • 1970-01-01
            相关资源
            最近更新 更多