Gabrielle
Gabrielle

Reputation: 4991

Fragment XXX {} not associated with a fragment manager

I started using navigation component in my application and I am facing with the following problem. My first fragment is LoginFragment. After a success login, the mainFragment is displayed. I want that when user is on mainFragment and press back button to not go back to loginFragment. For this I added these 2 lines in nav_graph : app:popUpTo="@+id/lovable_app_navigation" and app:popUpToInclusive="true" and it works well. Here is my navigation graph :

<?xml version="1.0" encoding="utf-8"?>
<navigation xmlns:android="http://schemas.android.com/apk/res/android"
  xmlns:app="http://schemas.android.com/apk/res-auto"
  xmlns:tools="http://schemas.android.com/tools"
  android:id="@+id/app_navigation"
  app:startDestination="@id/loginFragment">

  <fragment
    android:id="@+id/loginFragment"
    android:name="com.xxx.LoginFragment"
    android:label="LoginFragment"
    tools:layout="@layout/login_fragment">
    <action
      android:id="@+id/dashboard_action"
      app:destination="@id/mainFragment"
      app:launchSingleTop="true"
      app:popUpTo="@+id/app_navigation"
      app:popUpToInclusive="true"/>
  </fragment>

  <fragment
    android:id="@+id/mainFragment"
    android:name="com.xxx.MainFragment"
    android:label="MainFragment"
    tools:layout="@layout/main_fragment">
       <action
      android:id="@+id/logout_action"
      app:destination="@id/loginFragment"
      app:launchSingleTop="true"
      app:popUpTo="@+id/app_navigation"
      app:popUpToInclusive="true"/>
  </fragment>

  <action
    android:id="@+id/action_global_loginFragment"
    app:destination="@id/loginFragment" />
</navigation>

The problem is that after a time, when my session expires, it doesn't matter where the user is in application, in which fragment, I must to display the LoginFragment over the all stack. I created a global action for this action_global_loginFragment. The problem is that when I navigate to LoginFragment I get this error :

java.lang.IllegalStateException: Fragment LoginFragment{1d6bd24 (829a6832-3480-4bcb-a3f6-7e2ba214d3ca)} not associated with a fragment manager.

If I remove popUpTo and popUpToInclusive it works fine, but then the back button functionality is affected, from mainFragment it goes back to loginFragment. Any idea how to fixed this? Thanks in advance.

Upvotes: 24

Views: 29658

Answers (7)

Taha
Taha

Reputation: 144

In my case this issue was connected to MenuHost. If you use a new MenuHost/MenuProvider in your fragment/s, when you have multiple fragments with their menus, pressing menu item could invoke the item in inactive fragment. :

MenuHost menuHost = requireActivity();
    MenuProvider mm = new MenuProvider() {
        @Override
        public void onCreateMenu(@NonNull Menu menu, @NonNull MenuInflater menuInflater) {
            NavController navController = NavHostFragment.findNavController(YourFragment.this);
            if(navController.getCurrentDestination().getId()==R.id.yourfragmentid){
            menu.clear();
            menuInflater.inflate(R.menu.menu_main, menu);
            }
        }

        @Override
        public boolean onMenuItemSelected(@NonNull MenuItem item) {
            NavController navController = NavHostFragment.findNavController(ReportsFragment.this);
            if(navController.getCurrentDestination().getId()==R.id.reports) {
                return NavigationUI.onNavDestinationSelected(item, navController);
            }else {
                return false;
            }
        }
    };
    menuHost.addMenuProvider(
            mm,
            this.getViewLifecycleOwner(),
            Lifecycle.State.RESUMED
    );

Upvotes: 0

MOHSEN ALIAKBARI
MOHSEN ALIAKBARI

Reputation: 39

im cereate an extention for this issue , it work based on fragments lifecycle and kotlin

fun NavController.lifeCycleNavigate(lifecycle :LifecycleCoroutineScope, resId :Int) =
    lifecycle.launchWhenResumed {
        navigate(resId)
    }

now we can use it simply with navController , like this

findNavController().lifeCycleNavigate(lifecycleScope  , R.id.destination )

Upvotes: 0

Alex Trujillo
Alex Trujillo

Reputation: 75

I've had this issue too and its very confusing to know whats wrong!

I found this URL That helped me a lot!:Android Navigation Component Issue

This guy suggest to create a function on every fragment, due to when using the findNavController() with a fragment that isn't NavHostFragment or isn't within NavHostFragment this exception will be thrown.

fun Fragment.getFragmentNavController(@IdRes id: Int) = activity?.let {
    return@let Navigation.findNavController(it, id)
}

Then, you can all your navigation instance with the id just like this:

getFragmentNavController(R.id.shipping_host_nav).navigate(R.id.id_of_host_nav)

Upvotes: 0

Dr. Sa.M.
Dr. Sa.M.

Reputation: 2513

I was facing the same issue today. the problem was with the importing of the wrong file. there are actually 3 files that can be imported.

  1. import androidx.navigation.fragment.findNavController

    This says findNavController()

  2. import androidx.navigation.Navigation.findNavController

    This says findNavController(Activity, Int)

  3. import androidx.navigation.fragment.NavHostFragment.findNavController

    This says findNavController(Fragment)

If I used 2nd one it gave an error Fragment not attached/associated with/to an Activity. (don't remember the exact error)

If I used 3rd one I was getting the same error as @Gabrielle

so, for me, the first one worked perfectly fine since it doesn't require either Activity or Fragment.

Upvotes: 0

Amin Keshavarzian
Amin Keshavarzian

Reputation: 3963

for me the problem was the fragment after restoration because of config change was the fragment manager was not valid in fragment so I had to get it directly from activities like this:

activity?.findNavController(R.id.nav_host_fragment)?.navigate(....)

or

activity?.supportFragmentManager?.setFragmentResultListener(.....)

Upvotes: -1

Mohamed Eleish
Mohamed Eleish

Reputation: 331

The problem is caused when you try to call findNavController() on a fragment that has been detached, if you're using Kotlin you can create an extension function like so

fun Fragment.findNavControllerSafely(): NavController? {
    return if (isAdded) {
        findNavController()
    } else {
        null
    }
}

then use it in any fragment

findNavControllerSafely()?.navigate(/*pass here the nav directions>*/)

you can also surround it with try/catch but I do not recommend this as it will silently catch/ignore other exceptions that might be useful, try navigating through the source code of findNavController() to get a better feel of the kind of exceptions that are thrown

Upvotes: 11

Joscplan
Joscplan

Reputation: 1034

The same issue was happening to me, I managed to solve it by wrapping the navigate method inside a view?.post call like so:

view?.post {
    findNavController().navigate(SplashFragmentDirections.actionSplashFragmentToLoginFragment())
}

Upvotes: 24

Related Questions