FragmentContainerView using findNavController
AndroidAndroid LayoutAndroid FragmentsAndroid NavigationAndroid 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>