FragmentContainerView using findNavController

AndroidAndroid LayoutAndroid FragmentsAndroid Navigation

Android Problem Overview


I'm using Android Navigation Component with bottom navigation, lint gives a warning about replacing the <fragment> tag with <FragmentContainerView> but when i replaced, findNavController is not working it gives me error about it does not have a NavController set on

Fragment

<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:navGraph="@navigation/mobile_navigation" />

Activity

val navController = findNavController(R.id.nav_host_fragment)
    
    val appBarConfiguration = AppBarConfiguration(
        setOf(
            R.id.navigation_classes, R.id.navigation_schedule, R.id.navigation_settings
        )
    )
    setupActionBarWithNavController(navController, appBarConfiguration)
    navView.setupWithNavController(navController)
}

Android Solutions


Solution 1 - Android

As per this issue, when using FragmentContainerView, you need to find the NavController using findFragmentById() rather than using findNavController() when in onCreate():

val navHostFragment = supportFragmentManager.findFragmentById(R.id.nav_host_fragment) as NavHostFragment
val navController = navHostFragment.navController

This is because findNavController(R.id.nav_host_fragment) relies on the Fragment's View to already be created which isn't the case when using FragmentContainerView (as it uses a FragmentTransaction under the hood to add the NavHostFragment).

If you are using Fragment 1.4.0 or higher and View Binding, you can simply this considerably by using the getFragment() method:

val navController = binding.container.getFragment<NavHostFragment>().navController

Solution 2 - Android

Replace this line:

NavController navController = Navigation.findNavController(this, R.id.nav_host_fragment);

with

NavController navController = getNavController();

Where getNavController() looks like this:

    // workaround for https://issuetracker.google.com/issues/142847973
    @NonNull
    private NavController getNavController() {
        Fragment fragment = getSupportFragmentManager().findFragmentById(R.id.nav_host_fragment);
        if (!(fragment instanceof NavHostFragment)) {
            throw new IllegalStateException("Activity " + this
                    + " does not have a NavHostFragment");
        }
        return ((NavHostFragment) fragment).getNavController();
    }

Solution 3 - Android

On top of the accepted answer, a little shortcut what could be used is:

supportFragmentManager.findFragmentById(R.id.navHostMain)?.findNavController()

Regards

Solution 4 - Android

Add in your build.gradle (Module: App) this line

implementation "androidx.navigation:navigation-fragment-ktx:2.3.2"

and use this in activity

val navController = supportFragmentManager.findFragmentById(R.id.your_id_nav_host_fragment)
            ?.findNavController()

and in fragment

val navController = findNavController()

Solution 5 - Android

I solved my problen with extension:

fun FragmentActivity.findFragmentContainerNavController(@IdRes host: Int):NavController {
    try {
        val navHostFragment = supportFragmentManager.findFragmentById(host) as NavHostFragment
        return navHostFragment.findNavController()
    } catch (e: Exception) {
        throw IllegalStateException("Activity $this does not have a NavController set on $host")
    }
}

Solution 6 - Android

There's an even simpler way to @friederbluemle's answer. An assertion check should suffice.

NavHostFragment navHostFragment 
    = (NavHostFragment) getSupportFragmentManager().findFragmentById(R.id.nav_host_fragment);
assert navHostFragment != null : "navHostFragment not found";
NavController navController = navHostFragment.getNavController();

Solution 7 - Android

Here is the simple answer -

val navHostFragment = supportFragmentManager.findFragmentById(R.id.fragmentContainerView)

as NavHostFragment

val navController = navHostFragment.navControllermenus.setupWithNavController(navController)

Solution 8 - Android

use simple <fragment> tag instead of <androidx.fragment.app.FragmentContainerView>

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionJimale AbdiView Question on Stackoverflow
Solution 1 - AndroidianhanniballakeView Answer on Stackoverflow
Solution 2 - AndroidfriederbluemleView Answer on Stackoverflow
Solution 3 - AndroidJoao GavazziView Answer on Stackoverflow
Solution 4 - AndroidEvgenii DoikovView Answer on Stackoverflow
Solution 5 - AndroidYuri BarbosaView Answer on Stackoverflow
Solution 6 - AndroidHank ChanView Answer on Stackoverflow
Solution 7 - AndroidHarshidView Answer on Stackoverflow
Solution 8 - AndroidPawan Singh HarariyaView Answer on Stackoverflow