java.lang.IllegalStateException: Fragment 已经为 BottomSheetDialogFragment 添加了异常

Posted

技术标签:

【中文标题】java.lang.IllegalStateException: Fragment 已经为 BottomSheetDialogFragment 添加了异常【英文标题】:java.lang.IllegalStateException: Fragment already added exception for BottomSheetDialogFragment 【发布时间】:2021-01-15 15:49:56 【问题描述】:

为了在 BottomSheetDialogFragment 中显示最后一个状态,我尝试如下实现,

*) 活动:

    private var languageSelectorBsFragment: LanguageSelectorBsFragment? = null


    @OnClick(R.id.txt_imc_clip_language)
    fun onClickClipLanguage() 
        initLanguageBottomSheet()
        languageSelectorBsFragment?.show(supportFragmentManager, languageSelectorBsFragment!!.tag)
    

    private fun initLanguageBottomSheet() 
        if (languageSelectorBsFragment == null) 
           languageSelectorBsFragment = LanguageSelectorBsFragment.newInstance(LanguageSelectorBsFragment.TYPE_USER)
        
    

*) BottomSheetDialogFragment

class LanguageSelectorBsFragment : BottomSheetDialogFragment() 
   var lastSelectedLanguageId: String?;
   var userInputInEditText: String?;

因此只有一个 BottomSheetDialogFragment 实例,我需要保留上次打开底部工作表时用户与之交互的许多其他变量的引用。

通过执行上述步骤,我能够达到我们的要求,但有几次随机崩溃,我无法找到根本原因。

*) 例外:

Fatal Exception: java.lang.IllegalStateException: Fragment already added: LanguageSelectorBsFragment2b446ae (8fe75d96-932d-47eb-97af-128319431a55)
       at androidx.fragment.app.FragmentStore.addFragment(FragmentStore.java:67)
       at androidx.fragment.app.FragmentManager.addFragment(FragmentManager.java:1563)
       at androidx.fragment.app.BackStackRecord.executeOps(BackStackRecord.java:405)
       at androidx.fragment.app.FragmentManager.executeOps(FragmentManager.java:2167)
       at androidx.fragment.app.FragmentManager.executeOpsTogether(FragmentManager.java:1990)
       at androidx.fragment.app.FragmentManager.removeRedundantOperationsAndExecute(FragmentManager.java:1945)
       at androidx.fragment.app.FragmentManager.execPendingActions(FragmentManager.java:1847)
       at androidx.fragment.app.FragmentManager$4.run(FragmentManager.java:413)
       at android.os.Handler.handleCallback(Handler.java:751)
       at android.os.Handler.dispatchMessage(Handler.java:95)
       at android.os.Looper.loop(Looper.java:154)
       at android.app.ActivityThread.main(ActivityThread.java:6351)
       at java.lang.reflect.Method.invoke(Method.java)
       at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:896)
       at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:786)

我知道已经有很多问题存在完全相同的异常,我能想到的最接近的问题是this。

另外,我必须使用 BottomSheetDialogFragment 并且不能使用“Persistent Bottom Sheet”。我非常希望Android应该为“Modal Bottom Sheet”提供显示和隐藏功能,而不是每次关闭时都关闭。

*) 问题:

1)如何防止这种崩溃?

2) 有没有办法在不“关闭”的情况下“隐藏”模态底页?

【问题讨论】:

"另外,我必须使用 BottomSheetDialogFragment,不能使用"Persistent Bottom Sheet"。" - 如果您正在寻找“隐藏”而不是“解雇”,这是完全错误的,这就是为什么它们对于两个不同的用例是两个不同的东西 感谢您的及时回复。我可以想到很多用例,例如,可以在整个应用程序中使用的“过滤器”选择底部表。因此,我想让它独立,而不是只绑定一个活动。但是,如果用户在同一个活动中多次打开同一个底部工作表,则应该有一些方法来显示最后的选择选项。 我还观察到,BottomSheetDialogFragment 正在以某种方式执行此操作。因为如果我保持对 BottomSheetDialogFragment 的引用并且只显示()它,那么它会显示用户上次在 edittext 中输入的内容,如果我们传递相同的数据,还会显示 recyclerview 中项目的确切滚动位置。但我不确定如何? 【参考方案1】:

我自己也遇到过这个问题,这是我处理它的一种方式,也许它会对你有所帮助。 我必须在显示此对话框的Fragment 的整个生命周期中保持BottomSheetDialogFragment 的状态。

所以基本上,我创建了一个共享的ViewModel,片段有一个实例,显示的每个对话框都有相同的实例。 这样,您每次显示对话框时都可以获得相同的数据。 简单实现见here。

这样,您无需在活动中为对话框保存实例,只需通过ViewModel 访问对话框中的数据。它非常干净且易于维护。

【讨论】:

以上是关于java.lang.IllegalStateException: Fragment 已经为 BottomSheetDialogFragment 添加了异常的主要内容,如果未能解决你的问题,请参考以下文章