Search code examples
androidfragmentnavigation-drawer

How to open a fragment from another fragment using the Android Navigation Drawer?


I have anAndroid navigation drawer with a menu that tapping on items open fragments. Good so far. Some of those fragments need to open a new one for more details. I do that using this code from the first fragment:

getParentFragmentManager().beginTransaction().replace(R.id.nav_host_fragment_content_main, new MySecondFragment(), null).commit();

Tappin on the backbutton (the backarrow on the top-left corner) doesn't take me back to MyFirstFragment. It throughs an exceptions:

java.lang.IllegalStateException: Fragment MyFirstFragment not associated with a fragment manager.

I can use this other code:

getParentFragmentManager().beginTransaction().add(R.id.nav_host_fragment_content_main, new MySecondFragment(), null).commit();

But with this code both fragments are visible at the same time. I mean, MySecondFragment views are displayed but I see in the background MyFirstFragment views.

Any idea on how I can open MySecondFragment from MyFirstFragment , and then, if the back arrow is pressed I want to return to the same place MyFirstFragment was before.

Thanks


Solution

  • NEW ANSWER:

    Using the navigation drawer, it seems the fragment transactions happen under the NavHostFragment and its FragmentTransactionManager. This forces us to get its childFragmentManager() and use it for checking the backStackEntryCount.

    Therefore just adding the nested fragment to the parent backstack is not enough. We would need to override onBackPressed and onSupportNavigateUp and take into account the backstack of the NavHostFragment when going back and poping it.

        private fun handleNestedFragmentsBackStack(): Boolean {
            val navHostChildFragmentManager = supportFragmentManager
                .findFragmentById(R.id.nav_host_fragment_content_main)?.childFragmentManager
            
            return if (navHostChildFragmentManager?.backStackEntryCount!! > 1) {
                navHostChildFragmentManager.popBackStack()
                false
            } else {
                val navController = findNavController(R.id.nav_host_fragment_content_main)
                navController.navigateUp(appBarConfiguration) || super.onSupportNavigateUp()
            }
        }
    
        override fun onBackPressed() {
            handleNestedFragmentsBackStack()
        }
    
        override fun onSupportNavigateUp(): Boolean {
            return handleNestedFragmentsBackStack()
        }
    
    

    Now when adding your second fragment to the parent's backstack, remember that the parent isn't the Activity, but the NavHostFragment. You can proceed by doing the fragment transaction as suggested bellow in the initial answer.

    INITIAL ANSWER:

    Should work for standard fragment transactions

    Adding your fragment to the backstack should solve your issue

        FragmentTransaction ft = getParentFragmentManager().beginTransaction()
    
        ft.replace(R.id.nav_host_fragment_content_main, new MySecondFragment(), null)
        ft.addToBackStack(MySecondFragment.class.getName()) // you can use a string here, using the class name is just convenient 
        ft.commit();
    

    When pressing the back button, you will navigate through the back stack.

    The same in Kotlin code:

        parentFragmentManager.commit {
            replace(R.id.nav_host_fragment_content_main, MySecondFragment())
            addToBackStack(MySecondFragment::class.java.name)
        }