I have one case and wish to implement it by arch navigation component. For example I have 2 Nav Graphs (main and nested). Can I call main graph from nested and how?
I created an answer with the info devrocca provided. It's a full answer from scratch, i didn't skip anything if anyone ever needs.
This is the main fragment for navigation. Camera is direct destination without any nested graph, Dashboard has it's own nested graph but it's added to same backstack camera fragment is added. Home has 3 fragments with it's own nav host
MainActivity
|- MainNavHost
|- HomeNavHostFragment
| |- NestedNavHost
| |-HomeFragment1
| |-HomeFragment2
| |-HomeFragment3
|
|- nav_graph_dashboard
|
|- CameraFragment
Here is the navigation files
Main Navigation nav_graph.xml
Dashboard nested navigation graph
And nested navigation graph with it's own NavHost nav_graph_home
Layouts, i only add necessary ones, others are simple layouts with buttons, i add link for sample project with other navigation components samples included.
MainActivity
Main Fragment, this is first fragment that shown in the image used as start of main navigation
Layout that contains inner NavHostFragment for home navigation
MainActivity is for checking main navigation back stack, important thing here is
supportFragmentManager back stack is not updated as you navigate it's childFragmentManager even for main navigation, even if you only have one
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
// Get NavHostFragment
val navHostFragment =
supportFragmentManager.findFragmentById(R.id.main_nav_host_fragment)
// ChildFragmentManager of NavHostFragment
val navHostChildFragmentManager = navHostFragment?.childFragmentManager
navHostChildFragmentManager?.addOnBackStackChangedListener {
val backStackEntryCount = navHostChildFragmentManager.backStackEntryCount
val fragments = navHostChildFragmentManager.fragments
}
}
}
Fragment that contains Home navigation's host
class HomeNavHostFragment : BaseDataBindingFragment() {
override fun getLayoutRes(): Int = R.layout.fragment_home_navhost
private var navController: NavController? = null
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
val nestedNavHostFragment =
childFragmentManager.findFragmentById(R.id.nested_nav_host_fragment) as? NavHostFragment
navController = nestedNavHostFragment?.navController
navController?.navigate(R.id.homeFragment1)
listenBackStack()
}
private fun listenBackStack() {
// Get NavHostFragment
val navHostFragment =
childFragmentManager.findFragmentById(R.id.nested_nav_host_fragment)
// ChildFragmentManager of the current NavHostFragment
val navHostChildFragmentManager = navHostFragment?.childFragmentManager
navHostChildFragmentManager?.addOnBackStackChangedListener {
val backStackEntryCount = navHostChildFragmentManager!!.backStackEntryCount
val fragments = navHostChildFragmentManager!!.fragments
Toast.makeText(
requireContext(),
"HomeNavHost backStackEntryCount: $backStackEntryCount, fragments: $fragments",
Toast.LENGTH_SHORT
).show()
}
val callback = object : OnBackPressedCallback(true) {
override fun handleOnBackPressed() {
val backStackEntryCount = navHostChildFragmentManager!!.backStackEntryCount
Toast.makeText(
requireContext(),
"HomeNavHost backStackEntryCount: $backStackEntryCount",
Toast.LENGTH_SHORT
).show()
if (backStackEntryCount == 1) {
OnBackPressedCallback@ this.isEnabled = false
requireActivity().onBackPressed()
} else {
navController?.navigateUp()
}
}
}
requireActivity().onBackPressedDispatcher.addCallback(viewLifecycleOwner, callback)
}
}
There is one thing i don't know if it's improved in graph or code with nested NavHostFragment
If you set start destination of nav_graph_home HomeFragment1 instead of HomeNavHostFragment it works as dashboard which ignores nested NavHost and added to main back stack of fragments.
Since you are in inner NavHostFragment findNavController() in any home fragment returns the inner one
class HomeFragment3 : BaseDataBindingFragment() {
override fun getLayoutRes(): Int = R.layout.fragment_home3
private var count = 0
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
dataBinding.btnIncrease.setOnClickListener {
dataBinding.tvTitle.text = "Count: ${count++}"
}
val mainNavController =
Navigation.findNavController(requireActivity(), R.id.main_nav_host_fragment)
dataBinding.btnGoToStart.setOnClickListener {
//