IllegalStateException: Link does not have a NavController set

89,172

Solution 1

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"/>

Solution 2

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.

Solution 3

After doing some research I found this Issue also on Google's bugtracker. 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

Solution 4

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

Solution 5

Just replace <FrameLayout> With <fragment> and replace android:name="org.fossasia.openevent.app.core.auth.login.LoginFragment" with android:name="androidx.navigation.fragment.NavHostFragment"

Share:
89,172
Masquerade
Author by

Masquerade

Updated on December 24, 2021

Comments

  • Masquerade
    Masquerade over 2 years

    I'm using Android Navigation Component for Navigation. I have a LoginFragment which has a button to transition to SignUpFragment. On clicking the button I'm getting this error.

    java.lang.IllegalStateException: View android.support.v7.widget.AppCompatButton{49d9bd1 VFED..C.. ...P.... 201,917-782,1061 #7f090172 app:id/signUpLink} does not have a NavController set
    

    Here is my nav_graph.xml

    <navigation xmlns:app="http://schemas.android.com/apk/res-auto"
            xmlns:android="http://schemas.android.com/apk/res/android"
            xmlns:tools="http://schemas.android.com/tools"
            app:startDestination="@id/loginFragment">
            <fragment
                android:id="@+id/loginFragment"
                android:name="org.fossasia.openevent.app.core.auth.login.LoginFragment"
                android:label="login_fragment"
                tools:layout="@layout/login_fragment">
                <action
                    android:id="@+id/action_loginFragment_to_signUpFragment"
                    app:destination="@id/signUpFragment" />
    
            </fragment>
        </navigation>
    

    Here is the code in LoginFragment for Navigation -

    binding.signUpLink.setOnClickListener(Navigation.createNavigateOnClickListener(R.id.action_loginFragment_to_signUpFragment, null));
    

    Here is extract from activity layout file for NavHostFragment -

    <FrameLayout
        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="android.navigation.fragment.NavHostFragment"
        app:navGraph="@navigation/main_navigation"
        app:defaultNavHost="true"/>
    
  • Antek
    Antek over 5 years
    for me this unfortunately does not solve the problem - it's the same, actually
  • Peter
    Peter over 4 years
    This works fine, but will give a lint warning on the use of the <fragment> tag, stating that it should be replaced with a FragmentContainerView (although doing so will make your app crash).
  • heLL0
    heLL0 over 4 years
    android:name="androidx.navigation.fragment.NavHostFragment"
  • Johannes Büttner
    Johannes Büttner over 4 years
    @Peter I was able to solve this by upgrading gradle depedencies of material to implementation 'com.google.android.material:material:1.2.0-alpha04'.
  • hmac
    hmac about 4 years
    see here for reason why this is probably good advice: stackoverflow.com/questions/58703451/…
  • Siarhei
    Siarhei about 4 years
    had an exception with FragmentContainerView, but works fine with fragment. Also when used FragmentContainerView it give lint warning that app:navGraph not set, but no such warning with fragment
  • Vít Kapitola
    Vít Kapitola almost 4 years
    Works perfectly with Java and FragmentContainerView. (nav_version = "2.3.0")
  • Banana
    Banana almost 4 years
    In the issue linked they discuss why you shouldn't use fragment: issuetracker.google.com/issues/142847973#comment15: The Lint check is there exactly because you absolutely should switch over to FragmentContainerView in all cases.
  • Rawa
    Rawa almost 4 years
    @Justlearnedit Thanks, this was not clear at the point when I posted this answer. Thanks for updating me, I've tested the recommended solution and made sure to update the post to reflect it.
  • Sam Chen
    Sam Chen over 3 years
    Great explanation.
  • Big_Chair
    Big_Chair over 3 years
    "Method invocation 'getNavController' may produce 'NullPointerException'" so we always have to check for null before as well?
  • Rawa
    Rawa over 3 years
    @Big_Chair Not sure what method you are referring to. NavHostFragment has a getNavController() function which is annotated with NonNull. Maybe you are using an older version of Navigation?
  • Dr.jacky
    Dr.jacky over 3 years
    Check this answer and its comments: stackoverflow.com/a/59275182/421467
  • JCrooks
    JCrooks over 3 years
    The recommended solution worked for me on Nav 2.3.3, thank you for pointing that out!
  • Ticherhaz FreePalestine
    Ticherhaz FreePalestine about 3 years
    Somehow it fixed my problem.
  • Anwar Zahid
    Anwar Zahid about 3 years
    Wow!! After a lot of searching for two days, you buddies solve my problem. Thank you
  • Israel
    Israel about 3 years
    @Rawa It is not working for me. I am testing with navigation 2.3.5. I have seen many posts with this solution, Indeed Android documentation states like you had posted.
  • Israel
    Israel about 3 years
    I have cleaned, build and rebuild but it still not working.
  • jhfdr3s
    jhfdr3s about 3 years
    This also works when you receive null after minified or ofuscation. Try this.
  • user924
    user924 over 2 years
  • user924
    user924 over 2 years
  • HemangNirmal
    HemangNirmal over 2 years
  • Kimanthi K.
    Kimanthi K. over 2 years
    Fantastic way buddy
  • Moustafa EL-Saghier
    Moustafa EL-Saghier over 2 years
    this is working perfectly but, removed my toolbar and added one with back button, any idea how to fix this please?
  • user1154390
    user1154390 almost 2 years
    Thanks for saving my time , Ref here as well developer.android.com/guide/navigation/…