Android IllegalStateException:已在tabhost片段中添加片段

Android IllegalStateException:已在tabhost片段中添加片段,android,android-fragments,tabs,android-lifecycle,fragment-tab-host,Android,Android Fragments,Tabs,Android Lifecycle,Fragment Tab Host,所以,我有一个android应用程序,它是用tabhost构建的。总共有三个选项卡,在tab2中,有一个按钮用于在tab2中进行片段事务(它在片段活动中调用函数) 如果我这样运行,则会出现异常: <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_wi

所以,我有一个android应用程序,它是用tabhost构建的。总共有三个选项卡,在tab2中,有一个按钮用于在tab2中进行片段事务(它在片段活动中调用函数)

如果我这样运行,则会出现异常:

<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>
  • 在tab2中,我按下按钮来更改片段
  • 转到其他选项卡(如选项卡1或选项卡3)
  • 按后退按钮
  • 抛出异常

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

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

    FragmentTransaction t = getSupportFragmentManager().beginTransaction();
            t.replace(R.id.realtabcontent, mFrag);
            t.addToBackStack(null);
            t.commit();
    
    isAdded=如果片段当前已添加到其活动中,则返回true。取自官方文档。 如果已添加该片段,则不会添加该片段

    查看下面的链接以获取参考:

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

    就打电话

    if(!isAdded())
    {
        return;
    }
    

    话虽如此,我看不出有任何理由删除旧片段并再次添加相同的片段,因为我们可以通过简单地将参数传递到片段内的方法来更新UI/数据。有时,由于没有从相应的布局中找到正确的id,会发生这种情况。我面临这个问题。很多小时后,我发现我设置了错误的recyclerview id。我更改了它,对我来说效果很好


    所以,仔细检查你的片段布局

    在启动片段事务之前,您只需检查一个条件

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

    这对我来说非常有效…

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

     if (!fragmentOne.isAdded()){
                transaction = manager.beginTransaction();
                transaction.add(R.id.group,fragmentOne,"Fragment_One");
                transaction.commit();
     }
    
    对我来说,它的工作原理如下:

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

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

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

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

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

    override fun getItem(position: Int): Fragment {
        return tabs[0] // Right variant: tabs[position]
    }
    
    确保你没有犯同样的错误。

    按如下所示添加片段

    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();
    
    您可以尝试以下方法:

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

    如果不在FrameLayout内的视图组中包装正文XML,则会出现此错误

    错误:

     if (dialogFolderGallery.isAdded()) {
                    dialogFolderGallery.dismiss();
                } else { //bla...bla..
    }
    
    
    
    已解决:

    <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>
    
    
    

    希望这能帮助到其他人。

    我在片段中错误地使用ViewModel时出现了以下错误:

    <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>
    
    正确的方法:

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

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

    我试着通过点击按钮多次快速点击显示对话框片段

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


    可能的重复意味着backpress添加了一个新片段,backbackback中的逻辑是什么?谢谢,除了tab2之外,还有一个lotis mFrag被添加到其他选项卡?谢谢你的帮助,你的意思是我把if(!isAdded())放在oncreateview中了吗?是的,你只需要把我在上面的回答中提到的代码放进去……这意味着你的片段已经添加到堆栈中了。所以,不需要再次添加它,它只返回简单的值。这毫无意义,您不能在onCreateView中返回void,您是说onCreate吗?我在那里尝试了这个,但它对我的问题没有帮助。这是添加到
    onCreate
    ?为什么是否定符号?如果出现以下情况,不应该添加片段!isAdded()?这应该是公认的答案。被接受的答案毫无意义。首先,不应该对
    isAdded()
    进行否定。其次,在注释中,建议将此代码放入
    onCreate()
    ,这也是毫无意义的。这行代码应该直接放在添加(或替换)片段的行之前,而不是放在
    onCreate()
    onCreateView()
    中。在这两种方法中执行该代码已经太晚了。
    if(fragment.isAdded())fragmentTransaction.show(fragment)也必须检查隐藏片段。我需要添加相似的片段,只有片段中的属性不同。但是重复的错误仍然发生。我已经实现了检查片段是否已经添加,然后返回(添加片段的代码将不会执行),因为我的应用程序在play store上运行,但我仍然得到了崩溃片段已经从一些设备中添加,而不是从一个月前我试图找到的所有设备中添加,我无法克服,我已经应用了大量的解决方案,并在live play store上更新了构建,但我仍然收到了一些设备的错误,如Galaxy S20+5G、华为,我收到的问题设备较少,如果有任何帮助,我将不胜感激。谢谢,对我来说也是如此。异常消息非常具有误导性。在调查根本原因一个多月后,这就是原因。谢谢,我们不应该发送参数来对已经显示的片段进行任何更改吗?在片段被添加到片段管理器之后,您不能设置参数,而不是再次删除和添加它。来自docs:“如果片段被添加到FragmentManager,并且isStateSaved()将返回true,则无法调用此方法。”因此,如果要更新UI,则需要直接调用片段方法。是的,我不是指通过
    setArguments设置,而是指将参数作为参数发送以进行更新,所以删除和添加相同的片段没有用,对吗?这取决于。如果你需要重新配置很多东西,用一个新的片段替换这个片段可能会更容易。这完全取决于您的需要。如果使用一个事务,我将继续接收错误。这可能是由于使用片段管理器的异步行为造成的?它会用新的替换旧的吗?不,它不会替换,它会将以前的片段添加到后堆栈中。我想知道,这可能吗?昨天我尝试了类似的代码,但出现了一个错误,请参阅,因为
    addToBackStack
    不允许与
    commitNow
    一起使用。在该链接中,他手动禁用了back
                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");
                }