【问题标题】:IllegalStateException: Fragment already added in the tabhost fragmentIllegalStateException:已在 tabhost 片段中添加了片段
【发布时间】:2014-09-19 04:30:00
【问题描述】:
FATAL EXCEPTION: main
Process: com.example.loan, PID: 24169
java.lang.IllegalStateException: Fragment already added: FormFragment{428f10c8 #1 id=0x7f050055 form}
    at android.support.v4.app.FragmentManagerImpl.addFragment(FragmentManager.java:1192)
    at android.support.v4.app.BackStackRecord.popFromBackStack(BackStackRecord.java:722)
    at android.support.v4.app.FragmentManagerImpl.popBackStackState(FragmentManager.java:1533)
    at android.support.v4.app.FragmentManagerImpl$2.run(FragmentManager.java:489)
    at android.support.v4.app.FragmentManagerImpl.execPendingActions(FragmentManager.java:1484)
    at android.support.v4.app.FragmentManagerImpl$1.run(FragmentManager.java:450)
    at android.os.Handler.handleCallback(Handler.java:733)
    at android.os.Handler.dispatchMessage(Handler.java:95)
    at android.os.Looper.loop(Looper.java:136)
    at android.app.ActivityThread.main(ActivityThread.java:5068)
    at java.lang.reflect.Method.invokeNative(Native Method)
    at java.lang.reflect.Method.invoke(Method.java:515)
    at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:792)
    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:608)
    at dalvik.system.NativeStart.main(Native Method)

所以,我有一个使用 tabhost 构建的 android 应用程序。一共有三个tab,在tab2中,tab2中有一个进行fragment事务的按钮(就是调用fragment Activity中的函数)

FragmentTransaction t = getSupportFragmentManager().beginTransaction();
        t.replace(R.id.realtabcontent, mFrag);
        t.addToBackStack(null);
        t.commit();

如果我这样运行会有异常:

  1. 在tab2里面,我按下按钮来改变fragment
  2. 转到其他选项卡(例如选项卡 1 或选项卡 3)
  3. 按返回键
  4. 抛出异常

如何解决这个问题?感谢您的帮助

【问题讨论】:

标签: android android-fragments tabs android-lifecycle fragment-tab-host


【解决方案1】:

当我们在关闭之前尝试添加相同的片段或 DialogFragment 两次时会发生这种情况,

打个电话

if(mFragment.isAdded())
{
     return; //or return false/true, based on where you are calling from
}

话虽如此,我看不出有什么理由要删除旧片段并再次添加相同的片段,因为我们可以通过简单地将参数传递给片段内的方法来更新 UI/数据

【讨论】:

  • 这应该是公认的答案。接受的答案没有意义。首先,不能否定isAdded()。其次,在cmets中,建议这段代码进入onCreate(),这也是无稽之谈。这行代码应该直接放在添加(或替换)片段的行之前,而不是在onCreate()onCreateView() 中。在这两种方法中执行该代码都为时已晚。
  • if(fragment.isAdded()) fragmentTransaction.show(fragment);
  • 还必须检查隐藏片段。
  • 我需要添加相似的片段,只有片段中的属性不同。但是还是会出现重复的错误。
  • 我已经实现了检查是否已经添加了片段然后返回(添加片段的代码不会被执行),因为我的应用程序在 Play 商店中仍然存在,但我得到了崩溃片段已经从一些设备中添加,而不是我从一个月前试图弄清楚的所有设备,我无法克服它,我已经应用了许多解决方案并更新了现场游戏商店的构建,我仍然收到来自某些设备(如 Galaxy S20+ 5G、华为)的错误,我遇到问题的设备较少,感谢您提供任何帮助
【解决方案2】:

删除旧片段以防它仍然被添加,然后添加新片段:

FragmentManager fm = getSupportFragmentManager();
Fragment oldFragment = fm.findFragmentByTag("fragment_tag");
if (oldFragment != null) {
    fm.beginTransaction().remove(oldFragment).commit();
}
MyFragment newFragment = new MyFragment();
fm.beginTransaction().add(newFragment , "fragment_tag");

【讨论】:

  • 我们不应该发送参数来对已经显示的片段进行任何更改吗?而不是删除并再次添加它
  • 片段添加到片段管理器后不能设置参数。来自文档:“如果将片段添加到 FragmentManager 并且 isStateSaved() 将返回 true,则无法调用此方法。”所以如果你想更新 UI,你需要直接调用你的 Fragment 方法。
  • 是的,我不是说通过setArguments设置,是指将参数作为参数发送更新,所以删除和添加相同的片段没有用吗?
  • 视情况而定。如果您需要重新配置很多东西,只需将片段替换为新片段可能会更容易。这完全取决于您的需求。
  • 如果使用一笔交易,我会继续收到错误消息。这可能是由于片段管理器的异步工作行为所致。
【解决方案3】:

您只需检查下面提到的片段中的一个条件:

if(!isAdded())
{
    return;
}

isAdded = 如果片段当前已添加到其活动中,则返回 true。 取自官方文档。 如果已添加该片段,则不会添加该片段

查看以下链接以获取参考:
http://developer.android.com/reference/android/app/Fragment.html#isAdded()

【讨论】:

  • 谢谢你的帮助,你的意思是我把 if(!isAdded()) 放在 oncreateview 里面了吗?
  • 是的,您只需将我在上面的答案中提到的代码放入...这意味着您的片段已经添加到堆栈中。因此,无需再次添加它,它会简单地返回。
  • 这没有意义,你不能在onCreateView中返回void,你的意思是onCreate吗?我在那里尝试过,但对我的问题没有帮助
  • 这是添加到onCreate吗?
  • 为什么是否定符号?如果 !isAdded() 不应该添加片段吗?
【解决方案4】:

有时会因为没有从相应的布局中找到正确的 id 而发生。我遇到了这个问题。然后几个小时后我发现我设置了错误的recyclerview id。我改变了它,对我来说效果很好。

所以,请仔细检查您的片段布局。

【讨论】:

  • 谢谢,对我来说也是如此。异常消息的误导性再好不过了。
  • 经过一个多月的调查根本原因,原来是这个原因。非常感谢
  • 谢谢,这就是问题所在,异常消息将我们所有人带到这里只是为了发现视图 ID 错误,这很荒谬。
【解决方案5】:

您只需要在开始片段交易之前检查一个条件

 if (!fragmentOne.isAdded()){
            transaction = manager.beginTransaction();
            transaction.add(R.id.group,fragmentOne,"Fragment_One");
            transaction.commit();
 }

这对我来说非常有效......

【讨论】:

    【解决方案6】:

    当我没有将我的正文 XML 包装在 FrameLayout 内的 ViewGroup 中时,我遇到了这个错误。

    错误:

    <FrameLayout 
        xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:tools="http://schemas.android.com/tools"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        tools:context=".screens.home.HomeEpoxyFragment">
    
        <androidx.swiperefreshlayout.widget.SwipeRefreshLayout
            android:id="@+id/swipe_refresh_layout"
            android:layout_width="match_parent"
            android:layout_height="match_parent">
    
            <androidx.recyclerview.widget.RecyclerView
                android:id="@+id/rv"
                android:overScrollMode="never"
                android:layout_width="match_parent"
                android:layout_height="match_parent" />
    
        </androidx.swiperefreshlayout.widget.SwipeRefreshLayout>
    
    </FrameLayout>
    

    已解决:

    <FrameLayout 
        xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:tools="http://schemas.android.com/tools"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        tools:context=".screens.home.HomeEpoxyFragment">
    
        <androidx.constraintlayout.widget.ConstraintLayout
            android:layout_width="match_parent"
            android:layout_height="match_parent">
    
            <androidx.swiperefreshlayout.widget.SwipeRefreshLayout
                android:id="@+id/swipe_refresh_layout"
                android:layout_width="match_parent"
                android:layout_height="match_parent">
    
                <androidx.recyclerview.widget.RecyclerView
                    android:id="@+id/rv"
                    android:overScrollMode="never"
                    android:layout_width="match_parent"
                    android:layout_height="match_parent" />
    
            </androidx.swiperefreshlayout.widget.SwipeRefreshLayout>
        </androidx.constraintlayout.widget.ConstraintLayout>
    
    </FrameLayout>
    

    希望这可以帮助某人。

    【讨论】:

      【解决方案7】:

      这是我的对话框片段解决方案(您也可以将此概念用于片段类)

      我尝试多次快速点击显示对话框片段。

                  FragmentManager fm = getSupportFragmentManager();
                  Fragment oldFragment = fm.findFragmentByTag("wait_modal");
      
                  if(oldFragment != null && oldFragment.isAdded())
                      return;
      
                  if(oldFragment == null && !please_wait_modal.isAdded() && !please_wait_modal.isVisible()){
                      fm.executePendingTransactions();
                      please_wait_modal.show(fm,"wait_modal");
                  }
      

      【讨论】:

        【解决方案8】:

        对我来说是这样的:

        Fragment oldFragment = manager.findFragmentByTag(READER_VIEW_POPUP);
        if (oldFragment != null) {
            manager.beginTransaction().remove(oldFragment).commit();
        }
        
        FragmentTransaction ft = manager.beginTransaction();
        ft.add(this, tag);
        ft.commit();
        

        【讨论】:

          【解决方案9】:

          如果您在 ViewPagerFragmentStatePagerAdapter 中创建了一个已经存在的项目,它甚至会发生:

          override fun getItem(position: Int): Fragment {
              return tabs[0] // Right variant: tabs[position]
          }
          

          private val tabs: List&lt;Fragment&gt; 是选项卡中的片段列表)。

          【讨论】:

          • 你是怎么解决这个问题的?它与我的用例非常相似
          • @Mitch,我在第二行写了return tabs[position]
          • 我也在使用与return tabs[position]相同的概念,但它仍然会抛出错误
          • @Mitch,对不起,我不知道没有代码。对于一般情况,我目前使用stackoverflow.com/a/57161814/2914140。你认为FragmentStatePagerAdapter 会在getItem 中抛出错误吗?
          • 这很可能是错误的根源,因为它是检索ViewPager 显示的片段实例的位置
          【解决方案10】:

          令我惊讶的是,我两次调用片段事务时犯了一个愚蠢的错误:

          if (!FirebaseManager.isClientA && !FirebaseManager.isClientB) {
                fragment = new FragmentA();
                getFragmentManager().beginTransaction().add(R.id.fragment_frame, fragment, null).addToBackStack("").commit();
          } else if (FirebaseManager.isClientB) {
                fragment = new FragmentB();
          } else {
                fragment = new FragmentC();
          }
          getFragmentManager().beginTransaction().add(R.id.fragment_frame, fragment, null).addToBackStack("").commit();
          

          确保你不会犯同样的错误。

          【讨论】:

            【解决方案11】:

            添加片段如下

            FragmentTransaction t = getSupportFragmentManager().beginTransaction();
                t.replace(R.id.realtabcontent, mFrag);
                t.addToBackStack(null);
                t.commitNowAllowingStateLoss();
            

            【讨论】:

            • 新旧片段会发生什么?会用新的代替旧的吗?
            • 不,它不会替换它会将前一个片段添加到后台堆栈。
            • 我想知道,这可能吗?昨天试了类似的代码,报错,见stackoverflow.com/questions/38566628/…,因为addToBackStack不能和commitNow一起使用。
            • 在该链接中,他正在手动禁用后台堆栈。使用 addToBackStack 可以管理片段的回栈
            【解决方案12】:

            你可以试试这个:

             if (dialogFolderGallery.isAdded()) {
                            dialogFolderGallery.dismiss();
                        } else { //bla...bla..
            }
            

            【讨论】:

              【解决方案13】:

              在 Fragment 中错误地使用 ViewModel 时出现此错误,如下所示:

              //This is wrong!
              MyViewModel viewModel = new MyViewModel(getActivity().getApplication());
              

              正确方法:

              viewModel = new ViewModelProvider(this, ViewModelProvider.AndroidViewModelFactory.getInstance(getActivity().getApplication())).get(MyViewModel.class);
              

              【讨论】:

                【解决方案14】:

                不是很好的解决方案,但它有效)

                if(!ConfirmDataSync.isVisible) show()

                【讨论】:

                  猜你喜欢
                  • 2011-09-09
                  • 1970-01-01
                  • 1970-01-01
                  • 1970-01-01
                  • 1970-01-01
                  • 1970-01-01
                  • 1970-01-01
                  • 1970-01-01
                  • 1970-01-01
                  相关资源
                  最近更新 更多