Search code examples
androidandroid-fragmentsandroid-navigationandroid-navigation-graph

Is it possible to inflate a view that contains `FragmentContainerView` inside a `Fragment`?


I'm trying to inflate a view that contains FragmentContainerView inside a fragment that's being put into a layout.

  • RootView
    • Fragment
      • CustomView
        • FragmentContainerView

Like this:

val transaction = fragmentManager.beginTransaction()
transaction.replace(R.id.main_content, Frag(), "tag");
transaction.commitNowAllowingStateLoss()

where Frag creates a view that inflates a xml like this one:

<?xml version="1.0" encoding="utf-8"?>
<merge xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:parentTag="android.widget.FrameLayout">

    <androidx.fragment.app.FragmentContainerView
        android:id="@+id/nav_host_fragment"
        android:name="androidx.navigation.fragment.NavHostFragment"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        app:defaultNavHost="true"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        app:navGraph="@navigation/nav_graph" />
</merge>

But when I execute the code, my app crashes:

Caused by: java.lang.IllegalStateException: FragmentManager is already executing transactions


How can I avoid this error while using FragmentContainerView (obs.: if I use <fragment> instead of <androidx.fragment.app.FragmentContainerView>, everything works fine)


Solution

  • You should always, always use childFragmentManager when nesting fragments - the childFragmentManager is never executing transactions when its parent is going through lifecycle changes (which I assume is when you're calling your transaction).

    This is actually silently causing issues for you when you use the <fragment> tag as those lifecycle events don't actually occur as a transaction, but directly as part of inflation. Using the wrong FragmentManager means that the fragment and its views will not properly save and restore their state.

    The reason it fails with FragmentContainerView is that FragmentContainerView actually does the same FragmentTransaction as you'd do normally.