Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

IllegalStateException: Link does not have a NavController set

People also ask

What is NavController in Android?

NavController manages app navigation within a NavHost . Apps will generally obtain a controller directly from a host, or by using one of the utility methods on the Navigation class rather than create a controller directly. Navigation flows and destinations are determined by the navigation graph owned by the controller.

What is NAV host fragment?

NavHostFragment provides an area within your layout for self-contained navigation to occur. NavHostFragment is intended to be used as the content area within a layout resource defining your app's chrome around it, e.g.: <androidx.drawerlayout.widget.DrawerLayout.


Officially recommended solution

Currently using the FragmentContainerView is not very friendly, you have to access it from the supportFragmentManager:

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

In my xml my FragmentContainerView looks like this:

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

This has been tested with androidx navigation version 2.3.0

I've removed the old answer because it has been clarified by Google devs that it is not the recommended solution anymore. Thanks @Justlearnedit, for posting a comment allowing me to update this issue.


UPDATED SOLUTION

Actually, Navigation can't find NavController in FrameLayout. So replacing <FrameLayout> with <fragment> will make it work

Add the following inside the <fragment> tag -

android:name="androidx.navigation.fragment.NavHostFragment"

After doing the changes, the code will look similar to this -

 <fragment
       android:id="@+id/fragment_container"
       android:layout_width="match_parent"
       android:layout_height="match_parent"
       app:layout_behavior="@string/appbar_scrolling_view_behavior"
       android:name="androidx.navigation.fragment.NavHostFragment"
       app:navGraph="@navigation/main_navigation"
       app:defaultNavHost="true"/>

I've done some research and found this Issue also on Google. So here's the official solution in Java:

NavHostFragment navHostFragment = (NavHostFragment) getSupportFragmentManager()
                .findFragmentById(R.id.nav_host_fragment);
NavController navCo = navHostFragment.getNavController();

and here in kotlin:

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

The reason is that the fragment view isn't available inside the Activity.onCreate() method if you're adding it using FragmentContainerView (or just a FrameLayout). The proper way to get the NavController in this case is to find the NavHostFragment and get the controller from it. See the issue and the explanation.

override fun onCreate(savedInstanceState: Bundle?) {
   ...

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

Don't use <fragment> instead of <androidx.fragment.app.FragmentContainerView> as some other answers suggest. See the comment from the Google team in the issue I mentioned above.

You should always use FragmentContainerView. There are absolutely other fixes around window insets and layout issues that occur when a fragment's root layout is directly within other layouts such as ConstraintLayout, besides the underlying issues with the tag where fragments added via that tag go through lifecycle states entirely differently from the other Fragments added to the FragmentManager. The Lint check is there exactly because you absolutely should switch over to FragmentContainerView in all cases.

There's also an announcement from AndroidDevSummit 2019 which explains why FragmentContainerView was introduced, and another thread on SO about the difference: <androidx.fragment.app.FragmentContainerView> vs as a view for a NavHost