androidandroid-fragmentsandroid-activityandroid-architecture-navigationandroid-viewbinding

How to use NavHostFragment with FragmentContainerView?


I’m curious about an issue I’m having with Navigation Component, specifically on hosting NavHostFragment. I have a single-Activity native app with a few Fragments. I’m in the launcher’s xml, replacing the <fragment> with <androidx.fragment.app.FragmentContainerView>.

The initial implementation has worked as intended for a year. While introducing the FragmentContainerView this week the starting destination’s screen doesn’t render at launch. Yet I observe logs that prove successful data incoming from network and cache. From this state, only triggering configuration change by rotating the device renders UI as expected.

My AndroidX NavigationFragmentKtx and NavigationUiKtx dependencies are version 2.3.2. Relevant files abbreviated. Does anything stand out that I've missed? Any thoughts are appreciated.

launcher_activity.xml

<androidx.fragment.app.FragmentContainerView
        android:id="@+id/launcher_navHost"
        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_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        app:navGraph="@navigation/nav_graph" />

LauncherActivity.kt

class LauncherActivity : AppCompatActivity(R.layout.launcher_activity) {
    private lateinit var viewBinding: LauncherActivityBinding
    
    private val navController: NavController by lazy {
        val navHost = supportFragmentManager.findFragmentById(
            R.id.launcher_navHost
        ) as NavHostFragment
        navHost.navController
    }
        
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        viewBinding = LauncherActivityBinding.inflate(layoutInflater)
        setContentView(viewBinding.root)
    }
}

Solution

  • You're using AppCompatActivity(R.layout.launcher_activity), which means you are automatically calling setContentView(R.layout.launcher_activity) as part of super.onCreate(savedInstanceState) (that's what passing a layout ID does). You're then overriding that layout with a second call to setContentView().

    You can just remove the R.layout.launcher_activity part if you're using View Binding as it is not needed (and the root of your issue):

    class LauncherActivity : AppCompatActivity() {