IllegalStateException:该片段已添加到tabhost片段中


79
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应用。总共有三个选项卡,在tab2中,有一个用于在tab2中进行片段事务的按钮(正在片段活动中调用该函数)

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

如果我这样运行,则有例外:

  1. 在tab2里面,我按下按钮来更改片段
  2. 转到其他标签(例如标签1或标签3)
  3. 按下按钮
  4. 抛出异常

如何解决?感谢您的帮助



这意味着backpress正在添加一个新片段,backstack中的逻辑是什么?非常感谢
user782104

除了tab2之外,mFrag是否已添加到其他某些标签?
Akhil

Answers:


149

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

只是打电话

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

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


5
这应该是公认的答案。接受的答案没有任何意义。首先,不应否定isAdded()。其次,建议在注释中加入该代码onCreate(),这也是荒谬的。该行代码应直接放置在添加(或替换)片段的行之前,而不是onCreate()或中onCreateView()。在任何一种方法中执行该代码为时已晚。
AndroidDev 2015年

3
if(fragment.isAdded()) fragmentTransaction.show(fragment);
康斯坦丁·科诺普科

还必须检查隐藏片段。
Mahdi Moqadasi '19

我需要添加类似的片段,但片段中的属性不同。但是仍然出现重复的错误。
Alston

我已经实现了检查是否已经添加了片段然后返回的操作(添加片段的代码将不会执行),因为我的应用程序仍在Play商店中运行,但我还是从某些设备中添加了崩溃片段,我想从一个月前弄清所有设备,我无法克服,我已经应用了许多解决方案并更新了实时播放商店的内部版本,但我仍然从某些设备中收到错误像Galaxy S20 + 5G,华为,出现问题的设备很少,感谢您的帮助
纳文

12

如果仍要添加旧片段,请删除它,然后添加新片段:

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

我们不应该发送参数来对已经显示的片段进行任何更改吗?而不是删除并再次添加
-Ujju,

将片段添加到片段管理器后,您将无法设置参数。来自文档:“如果将片段添加到FragmentManager且isStateSaved()返回true,则无法调用此方法。” 因此,如果要更新UI,则需要直接调用片段方法。
vovahost

是的,我的意思不是通过via设置setArguments是指将参数作为参数进行更新,因此删除和添加相同的片段没有用处吗?
Ujju

这取决于。如果您需要重新配置很多东西,将片段替换为新片段可能会更容易。这完全取决于您的需求。
vovahost

1
如果使用一项交易,我将继续收到错误消息。可能是由于使用片段管理器的异步行为。
CoolMind

8

您只需要检查下面提到的片段中的一种情况:

if(!isAdded())
{
    return;
}

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

检查下面的链接以获取参考:http :
//developer.android.com/reference/android/app/Fragment.html#iwego()


谢谢您的帮助,您是说我将if(!i⚓())放在oncreateview中吗?
user782104 2014年

是的,您只需要放入我在上面的答案中提到的代码...这意味着您的片段已添加到堆栈中。因此,无需再次添加它,它只会返回。
Deep Mehta 2014年

6
这没有任何意义,您不能在onCreateView中返回void,您的意思是onCreate吗?我在那里尝试过,但并没有解决我的问题
Fonix 2015年

5
这是添加到onCreate吗?
StuStirling

5
为什么要取反符号?如果不添加片段!
艾伦·西雅克

7

有时是因为没有从相应的布局中找到正确的ID。我遇到了这个问题。然后许多小时后,我发现我设置了错误的recyclerview ID。我更改了它,并且对我来说效果很好。

因此,请仔细检查您的片段布局。


2
谢谢,对我来说也是一样。异常消息不会造成更多误导。
SqueezyMo

经过一个多月的调查根本原因,这就是原因。非常感谢
Omid Heshmatinia

7

您只需要在开始片段交易之前检查一种情况

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

这对我来说是完美的工作...


1

不将我的主体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>

希望这可以帮助某人。


0

对我来说,它的工作原理是:

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

0

如果FragmentStatePagerAdapterViewPager在中创建了一个已经存在的项目,甚至会发生这种情况:

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

private val tabs: List<Fragment>是选项卡中片段的列表)。


您是如何解决的?这与我的用例非常相似
Mitch19,19年

@Mitch,我return tabs[position]在第二行中写道。
CoolMind

我还使用相同的概念return tabs[position],但它仍然抛出一个错误
米奇

@Mitch,对不起,没有代码我也不知道。对于一般情况,当前我使用stackoverflow.com/a/57161814/2914140。您认为FragmentStatePagerAdapter会引发错误getItem吗?
CoolMind

这很可能是错误的根源,因为它是在其中ViewPager检索到所示片段的实例的地方
Mitch19,19年

0

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

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

确保您没有犯同样的错误。


0

如下添加片段

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

新旧片段会发生什么?它将用新旧替代旧吗?
CoolMind

不,它不会替代它将之前的片段添加到堆栈中。
M.Noman

我想知道,有可能吗?昨天我尝试了类似的代码,但出现错误,请参见stackoverflow.com/questions/38566628/…,因为addToBackStack不允许与一起使用commitNow
CoolMind

在该链接中,他正在手动禁用后堆栈。使用addToBackStack,它将能够管理片段的后向堆栈
M.Noman

0

您可以尝试以下方法:

 if (dialogFolderGallery.isAdded()) {
                dialogFolderGallery.dismiss();
            } else { //bla...bla..
}
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.