Search code examples
androidandroid-fragmentsandroid-jetpack-compose

Loading Fragment in Compose, it called commit several times


I tried to load a Fragment in Compose as below, through the supportFragmentManager as shown below.

class MainActivity : FragmentActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContent {
            AndroidViewBinding(FragmentContainerBinding::inflate) {
                supportFragmentManager.beginTransaction()
                    .replace(container.id, MyFragment()).commit()
                }
        }
    }
}

However, when the view is shown, the fragment gets committed (loaded) several times (i.e. the onCreate() is called several times)

Any way to prevent committing several times? Is there a way to resume the state as well (e.g. in case got killed by the system, how to get it restored)?

(note: I'm not using the androidx.fragment.app.FragmentContainerView in the XML as in Developer Doc I do have different fragments per some logic (not shown here), hence I'll have to use supportFragmentManager)


Solution

  • Found a way to get this working

    class MainActivity : FragmentActivity() {
        override fun onCreate(savedInstanceState: Bundle?) {
            super.onCreate(savedInstanceState)
            setContent {
                FragmentContainer(
                    modifier = Modifier.fillMaxSize(),
                    fragmentManager = supportFragmentManager,
                    commit = { add(it, MyFragment()) }
                )
            }
        }
    }
    
    @Composable
    fun FragmentContainer(
        modifier: Modifier = Modifier,
        fragmentManager: FragmentManager,
        commit: FragmentTransaction.(containerId: Int) -> Unit
    ) {
        val containerId by rememberSaveable { mutableStateOf(View.generateViewId()) }
    
        AndroidView(
            modifier = modifier,
            factory = { context ->
                fragmentManager.findFragmentById(containerId)?.view
                    ?.also { (it.parent as? ViewGroup)?.removeView(it) }
                    ?: FragmentContainerView(context)
                        .apply { id = containerId }
                        .also {
                            fragmentManager.commit { commit(it.id) }
                        }
            }
        )
    }
    

    Note this will need Fragment's KTX

        implementation "androidx.fragment:fragment-ktx:1.4.1"