java.lang.IllegalStateException: Fragment already added exception for BottomSheetDialogFragment

1.2k views Asked by At

In order to show a last state in a BottomSheetDialogFragment I try to implement as below,

*) Activity:

    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?;
}

So that there is only one instance of BottomSheetDialogFragment and I need to keep a reference of many othervariables that the user has interacted with when the bottom sheet last time opened.

By doing the above steps I am able to achieve our requirement but several times it is randomly crashing and I am unable to find the root cause.

*) Exception:

Fatal Exception: java.lang.IllegalStateException: Fragment already added: LanguageSelectorBsFragment{2b446ae} (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)

I know there are already many existing questions with an exact similar exception and the closest which I can think of is this.

Also, I have to use BottomSheetDialogFragment and can not use "Persistent Bottom Sheet". I seriously hope that Android should provide show and hide feature for "Modal Bottom Sheet" and not dismiss every time it closes.

*) Questions:

1) How to prevent this crash?

2) Is there a way to "hide" Modal Bottom Sheet without "dismiss"?

1

There are 1 answers

0
baltekg On

I had this problem myself and this is a way I handled it, maybe it will help you.
I had to keep state of the BottomSheetDialogFragment throughout the lifecycle of the Fragment that this dialog was showing on top of.

So basically, I created a shared ViewModel that there is one instance of it for the fragment and the same instance for each dialog that is shown.
This way, you can have same data every time you show the dialog.
Simple implementation is shown here.

This way, you don't need to hold an instance to a dialog in your activity and just access the data in the dialog via the ViewModel. It's really clean and easy to maintain.