{"id":19521796,"url":"https://github.com/smarttoolfactory/navigationcomponents-tutorials","last_synced_at":"2025-04-05T08:06:21.045Z","repository":{"id":38343144,"uuid":"203872063","full_name":"SmartToolFactory/NavigationComponents-Tutorials","owner":"SmartToolFactory","description":"Tutorials about Navigation Components to learn using nav graphs, adding top menus, passing arguments via safe args, combining with different Material Design widgets such as BottomNavigationView, Toolbar, ViewPager2, TabLayout and dynamic feature module navigation with DynamicNavHostFragment and examining Memory Leaks.","archived":false,"fork":false,"pushed_at":"2024-03-25T08:09:01.000Z","size":37804,"stargazers_count":398,"open_issues_count":3,"forks_count":91,"subscribers_count":7,"default_branch":"master","last_synced_at":"2025-03-29T07:04:38.350Z","etag":null,"topics":["android","android-bottom-navigation","android-fragment-factory","android-jetpack-navigation","android-navigation","android-navigation-component","bottomnavigationview","dynamic-feature-module","dynamic-features","navhostfragment","nested-fragments","tablayout-androidx","viewpager2"],"latest_commit_sha":null,"homepage":"","language":"Kotlin","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/SmartToolFactory.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE.md","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2019-08-22T20:55:58.000Z","updated_at":"2025-03-20T16:01:59.000Z","dependencies_parsed_at":"2024-03-25T09:39:49.424Z","dependency_job_id":null,"html_url":"https://github.com/SmartToolFactory/NavigationComponents-Tutorials","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/SmartToolFactory%2FNavigationComponents-Tutorials","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/SmartToolFactory%2FNavigationComponents-Tutorials/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/SmartToolFactory%2FNavigationComponents-Tutorials/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/SmartToolFactory%2FNavigationComponents-Tutorials/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/SmartToolFactory","download_url":"https://codeload.github.com/SmartToolFactory/NavigationComponents-Tutorials/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247305933,"owners_count":20917208,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["android","android-bottom-navigation","android-fragment-factory","android-jetpack-navigation","android-navigation","android-navigation-component","bottomnavigationview","dynamic-feature-module","dynamic-features","navhostfragment","nested-fragments","tablayout-androidx","viewpager2"],"created_at":"2024-11-11T00:34:58.437Z","updated_at":"2025-04-05T08:06:21.007Z","avatar_url":"https://github.com/SmartToolFactory.png","language":"Kotlin","readme":"# Navigation Components Tutorials\nTutorials for learning Navigation Components starting with simple set up, continues with adding top menus, passing arguments via navigation graphs and combining them with different Material Design widgets such as ```BottomNavigationView```, ```Toolbar```, ```ViewPager2```, ```TabLayout``` and **dynamic feature module** navigation with ```DynamicNavHostFragment```.\n\n## Overview\n* Add, navigation graph and navigate to fragments with actions and animations\n    * [Tutorial1-1Navigation-NavGraph](https://github.com/SmartToolFactory/NavigationComponents-Tutorials/tree/master/Tutorial1-1Navigation-NavGraph)\n\n* Nested navigation graphs, NavHostFragment and navigation\n    * [Tutorial1-2Navigation-NestedNavGraph](https://github.com/SmartToolFactory/NavigationComponents-Tutorials/tree/master/Tutorial1-3Navigation-NestedNavHost)\n\n* Nested navigation with a NavHostFragment and back press handled with OnBackPressedCallback\n    * [Tutorial1-3Navigation-NestedNavHost](https://github.com/SmartToolFactory/NavigationComponents-Tutorials/tree/master/Tutorial1-3Navigation-NestedNavHost)\n\n* Set navigation with toolbar, NavigationView and use top menu buttons to navigate\n    * [Tutorial4-1NavigationUI-NavigationView](https://github.com/SmartToolFactory/NavigationComponents-Tutorials/tree/master/Tutorial4-1NavigationUI-NavigationView)\n\n* BottomNavigationView with simple navigation\n    * [Tutorial5-1NavigationUI-BottomNavigation](https://github.com/SmartToolFactory/NavigationComponents-Tutorials/tree/master/Tutorial5-1NavigationUI-BottomNavigation)\n\n* BottomNavigation with extension to create individual NavHostFragments and listen back stack changes\n    * [Tutorial5-3NavigationUI-BottomNavigation-NestedNavigation](https://github.com/SmartToolFactory/NavigationComponents-Tutorials/tree/master/Tutorial5-3NavigationUI-BottomNavigation-NestedNavigation)\n\n* Examine memory leaks when extension function setupWithNavController for BottomNavigationView is inside a fragment\n    * [Tutorial5-4NavigationUI-MemoryLeakCheck](https://github.com/SmartToolFactory/NavigationComponents-Tutorials/tree/master/Tutorial5-4NavigationUI-MemoryLeakCheck)\n\n* ViewPager2 inside a fragment with single navigation graph, navigates from the fragment ViewPager2 is in to next one\n    * [Tutorial6-0NavigationUI-ViewPager2](https://github.com/SmartToolFactory/NavigationComponents-Tutorials/tree/master/Tutorial6-0NavigationUI-ViewPager2)\n\n* Same tutorial as the previous one but data binding used this time to examine and solve memory leaks due to data binding\n    * [Tutorial6-1NavigationUI-ViewPager2](https://github.com/SmartToolFactory/NavigationComponents-Tutorials/tree/master/Tutorial6-1NavigationUI-ViewPager2)\n\n* ViewPager2 navigation with each page has it's own back stack or fragment that wraps/contains NavHostFragment\n    * [Tutorial6-2NavigationUI-ViewPager2-NestedNavHost](https://github.com/SmartToolFactory/NavigationComponents-Tutorials/tree/master/Tutorial6-2NavigationUI-ViewPager2-NestedNavHost)\n\n* ViewPager2 navigation with each page has it's own back stack or fragment that wraps/contains NavHostFragment\n    * [Tutorial6-2NavigationUI-ViewPager2-NestedNavHost](https://github.com/SmartToolFactory/NavigationComponents-Tutorials/tree/master/Tutorial6-2NavigationUI-ViewPager2-NestedNavHost)\n\n* ViewPager2 inside an Activity, and topbar title and current NavController is set using a liveData(This does not work after rotation)\n    * [Tutorial6-3NavigationUI-ViewPager2-Appbar-NestedNavigation-LiveData](https://github.com/SmartToolFactory/NavigationComponents-Tutorials/tree/master/Tutorial6-3NavigationUI-ViewPager2-Appbar-NestedNavigation-LiveData)\n\n* ViewPager2 and fragments with their own Toolbar, FragmentTransactionCallback is used for navigating ViewPager2 pages back stack properly\n    * [Tutorial6-4NavigationUI-ViewPager2-FragmentToolbar-NestedNavigation](https://github.com/SmartToolFactory/NavigationComponents-Tutorials/tree/master/Tutorial6-4NavigationUI-ViewPager2-FragmentToolbar-NestedNavigation)\n\n* ViewPager2 navigation when both it's child fragments and parent fragment have Toolbar of their own, and navigation from differnt layers\n    * [Tutorial6-5NavigationUI-ViewPager2-FragmentToolbar-MixedNavigation](https://github.com/SmartToolFactory/NavigationComponents-Tutorials/tree/master/Tutorial6-5NavigationUI-ViewPager2-FragmentToolbar-MixedNavigation)\n\n* ViewPager2 and TabLayout complex navigation with changing navigation in fragments different layers of navigation\n    * [Tutorial6-6NavigationUI-ViewPager2-Appbar-MixedNavigation-ViewModel](https://github.com/SmartToolFactory/NavigationComponents-Tutorials/tree/master/Tutorial6-6NavigationUI-ViewPager2-Appbar-MixedNavigation-ViewModel)\n\n* BottomNavigationView using ViewPager2 to have tabs with their own back stack.\n    * [Tutorial7-1BNV-ViewPager2-NestedNavigation](https://github.com/SmartToolFactory/NavigationComponents-Tutorials/tree/master/Tutorial7-1BNV-ViewPager2-NestedNavigation)\n\n* BottomNavigationView navigation through it's tabs, and navigating ViewPager2 is inside a tab of BottomNavigationView.\n    * [Tutorial7-2BNV-ViewPager2-ComplexArchitecture](https://github.com/SmartToolFactory/NavigationComponents-Tutorials/tree/master/Tutorial7-2BNV-ViewPager2-ComplexArchitecture)\n\n* Using REST api, complex navigation with layers(Total 3 layers of navigation) when ViewPager2 is inside a tab of BottomNavigationView\n    * [Tutorial7-3BNV-ViewPager2-FragmentToolbar-MixedNavigation](https://github.com/SmartToolFactory/NavigationComponents-Tutorials/tree/master/Tutorial7-3BNV-ViewPager2-FragmentToolbar-MixedNavigation)\n\n* Implementation of Dynamic Feature Module navigation, passing data and using SavedStateHandle to get data on back press\n    * [Tutorial8-1DynamicFeatures-Navigation](https://github.com/SmartToolFactory/NavigationComponents-Tutorials/tree/master/Tutorial8-1DynamicFeatures-Navigation)\n\n*  Using REST api, complex navigation with layers with ViewPager2 in BottomNavigationView and Dynamic Feature Modules.\n    * [Tutorial8-2DynamicFeatures-ComplexArchitecture](https://github.com/SmartToolFactory/NavigationComponents-Tutorials/tree/master/Tutorial8-2DynamicFeatures-ComplexArchitecture)\n\n## Tutorial Coverage\n\n### [Tutorial0-0MaterialDesign](https://github.com/SmartToolFactory/NavigationComponents-Tutorials/tree/master/Tutorial0-0MaterialDesign)\nCovers basic BottomNavigationView and ViewPager usage without any navigatiom components. This is a little bit like warm up before moving to more complex ones including navigation with ViewPager2\n\n### [Tutorial1-Navigation-NavGraph](https://github.com/SmartToolFactory/NavigationComponents-Tutorials/tree/master/Tutorial1-1Navigation-NavGraph)\nCovers how to use create navigation graph ```nav_graph.xml``` inside navigation folder, and  ```NavHostFragment```in ```activity_main.xml``` layout file.\n\n### Note\nOne important note to add is navigation uses FragmentTransaction.replace() to navigate next fragment inside specified ```NavHostFragment```\n\n```\n    \u003candroidx.fragment.app.FragmentContainerView\n        android:id=\"@+id/nav_host_fragment\"\n        android:name=\"androidx.navigation.fragment.NavHostFragment\"\n        android:layout_width=\"0dp\"\n        android:layout_height=\"0dp\"\n        app:layout_constraintBottom_toBottomOf=\"parent\"\n        app:layout_constraintLeft_toLeftOf=\"parent\"\n        app:layout_constraintRight_toRightOf=\"parent\"\n        app:layout_constraintTop_toTopOf=\"parent\"\n\n        app:defaultNavHost=\"true\"\n        app:navGraph=\"@navigation/nav_graph\" /\u003e\n```\n\nThere are multiple ways to navigate from one fragment to another using a ```NavController```, for instance\n\n```\n\nbuttonCenter?.setOnClickListener {\n\n    val options = navOptions {\n        anim {\n            enter = R.anim.slide_in_right\n            exit = R.anim.slide_out_left\n            popEnter = R.anim.slide_in_left\n            popExit = R.anim.slide_out_right\n        }\n    }\n\n    findNavController().navigate(R.id.middle1_dest, null, options)\n}\n\n```\n\nCheck out this tutorial if you wish to get familiar with basic consepts, animation and navigating with ```popUpTo```and ```popUpToInclusive```\n\n### [Tutorial1-2Navigation-NestedNavGraph](https://github.com/SmartToolFactory/NavigationComponents-Tutorials/tree/master/Tutorial1-3Navigation-NestedNavHost)\n\nUses seperate and nested fragments with each it's own navigation graph.\n\n```nav_graph``` is the main graph for navigation has navigation to **CameraFragment** or other graphs such as ```nav_graph_dashboard``` or ```nav_graph_home```\nNested graphs are part of the same ```navHostFragment?.childFragmentManager```\n\n### [Tutorial1-3Navigation-NestedNavHost](https://github.com/SmartToolFactory/NavigationComponents-Tutorials/tree/master/Tutorial1-3Navigation-NestedNavHost)\n\nCovers how nested graphs with their own back stack or ```NavHostFragment``` work. You can check out both main and home childFragmentManager back stack entry and fragment count by examining Toast or log messages.\n\n### Note\nMain graph back stack is controlled by ```NavHostFragment.getChildFragmentManager```\n\nWhen a nested navigation graph or ```NavHostFragment``` is added it's back stack is retrieved\nusing a childFragmentManager.\n\nWhen a fragment is from a nested navigation graph is on screen when you navigate back or forth it's current position\nchanges only for the current NavHostFragment, main back stack does not change.\n\n ```\n val callback = object : OnBackPressedCallback(false) {\n\n    override fun handleOnBackPressed() {\n\n        // Get NavHostFragment\n        val navHostFragment =\n            childFragmentManager.findFragmentById(nestedNavHostFragmentId)\n        // ChildFragmentManager of the current NavHostFragment\n        val navHostChildFragmentManager = navHostFragment?.childFragmentManager\n\n        // Check if it's the root of nested fragments in this navhosts\n        if (navController?.currentDestination?.id == navController?.graph?.startDestination) {\n\n            /*\n                Disable this callback because calls OnBackPressedDispatcher\n                 gets invoked  calls this callback  gets stuck in a loop\n             */\n            isEnabled = false\n            requireActivity().onBackPressed()\n            isEnabled = true\n\n        } else if (isVisible) {\n            navController?.navigateUp()\n        }\n\n    }\n}\n\n ```\n\n### Note\nBack navigation does NOT work for the first fragment in back stack of ```HomeNavHostFragment``` for this example, because\n\n ```\nif (navController!!.currentDestination == null || navController!!.currentDestination!!.id == navController!!.graph.startDestination) {\n    navController?.navigate(R.id.homeFragment1)\n}\n ```\n\nand start destination is ```HomeNavHostFragment```itself , but  last fragment, currentDestination on graph is  ```HomeFragment1``` when back button is pressed while ```HomeFragment2``` is on screen.\n\nChange ```app:startDestination=\"@id/home_dest\"``` to ```app:startDestination=\"@id/homeFragment1\"```  to solve back press issue for ```HomeNavHostFragment```, it's just set to demonstrate how start destination change back press.\n\n  ```\n \u003cnavigation xmlns:android=\"http://schemas.android.com/apk/res/android\"\n        xmlns:app=\"http://schemas.android.com/apk/res-auto\"\n        xmlns:tools=\"http://schemas.android.com/tools\"\n        android:id=\"@+id/nav_graph_home\"\n        app:startDestination=\"@id/home_dest\"\u003e\n\n    \u003cfragment\n            android:id=\"@+id/home_dest\"\n            android:name=\"com.smarttoolfactory.tutorial1_3navigation_nestednavhost.navhost.HomeNavHostFragment\"\n            android:label=\"HomeHost\"\n            tools:layout=\"@layout/fragment_navhost_home\" /\u003e\n\n    \u003cfragment\n            android:id=\"@+id/homeFragment1\"\n            android:name=\"com.smarttoolfactory.tutorial1_3navigation_nestednavhost.blankfragment.HomeFragment1\"\n            android:label=\"HomeFragment1\"\n            tools:layout=\"@layout/fragment_home1\"\u003e\n\n    \u003c/fragment\u003e\n\n\u003c/navigation\u003e\n ```\n\n### [Tutorial6-0NavigationUI-ViewPager](https://github.com/SmartToolFactory/NavigationComponents-Tutorials/tree/master/Tutorial6-0NavigationUI-ViewPager)\n\n**Navigation Architecture**\n\n```\nMainActivity (Appbar + Toolbar)\n|- MainNavHost\n    |\n    | FragmentViewPagerContainer(ViewPager2 + TabLayout)\n        |- HomeFragment1 -\u003e HomeFragment2 -\u003e HomeFragment3\n        |- DashboardFragment1 -\u003e DashboardFragment2 -\u003e DashboardFragment3\n```\n\nCovers how to create a ```ViewPager2```with navigation in main back stack, in this example ```ViewPager2```pages do not have their own back stacks. It's covered in tutorial Tutorial6-2.\n\n\n\u003cp align=\"center\"\u003e\n    \u003cimg src=\"./screenshots/Tutorial6-0.gif\"/\u003e\n\u003c/p\u003e\n\n### [Tutorial6-1NavigationUI-ViewPager](https://github.com/SmartToolFactory/NavigationComponents-Tutorials/tree/master/Tutorial6-1NavigationUI-ViewPager2)\n\nSame as previous tutorial except only with one difference,  ```data binding``` is used for binding.\n\n### Note\nData binding that is not null(or non-nullable) after ```Fragment.onDestroyView``` when ```ViewPager2```is inside a fragment causing leak canary to show data binding related **MEMORY LEAK** for this fragment when used in ```ViewPager2```. Also you need to set adapter of ViewPager2 either to prevent memory leaks, and another one is due to TabLayouts which is covered in later sections. Check out this [stackoverflow question](https://stackoverflow.com/questions/62851425/viewpager2-inside-a-fragment-leaks-after-replacing-the-fragment-its-in-by-navig) for more details.\n\n### [Tutorial6-2NavigationUI-NestedNavHost](https://github.com/SmartToolFactory/NavigationComponents-Tutorials/tree/master/Tutorial6-2NavigationUI-NestedNavHost)\n\n**Navigation Architecture**\n\n```\n\n MainActivity (Appbar + Toolbar)\n    |- MainNavHost\n       |\n       |- ViewPagerContainerFragment(ViewPager2 + TabLayout)\n       |   |- HomeNavHostFragment\n       |   |  |- HF1 -\u003e HF2 -\u003e HF3\n       |   |\n       |   |- DashboardNavHostFragment\n       |   |  |- DF1 -\u003e DF2 -\u003e DF3\n       |   |\n       |   |- NotificationHostFragment\n       |   |  |- NF1 -\u003e NF2 -\u003e NF3\n       |   |\n       |   |-LoginFragment1\n       |\n       |- LoginFragment1 -\u003e LoginFragment2\n```\n\nCovers ```ViewPager2``` and it's pages each with it's own back stack or navigation graphs.\n\n```\nNavHostFragment use NavController to navigate back/forth in any page.\n```\n\n\u003cp align=\"center\"\u003e\n    \u003cimg src=\"./screenshots/Tutorial6-2.gif\"/\u003e\n\u003c/p\u003e\n\n### Note\nThis tutorial has very important aspects for ```ViewPager2``` navigation\n\n1. Creating ```NavHostFragment``` for each page and can navigate inside them, each page has\n    it's own nav graph.\n\n    in each layout file ```NavHostFragment``` inside is retrieved using\n    ```\n            val nestedNavHostFragment =\n                childFragmentManager.findFragmentById(nestedNavHostFragmentId) as? NavHostFragment\n            navController = nestedNavHostFragment?.navController`\n    ```\n\n    ```HomeNavHostFragment``` uses the first fragment that is displayed on screen **HomeFragment1 while   ```DashboardNavHostFragment``` uses graph with itself as start destination so it should check for the ```NavController.getCurrentDestination()``` to navigate to it when device rotated\n\n    ```LoginFragment1``` is added to main graph, because of that appbar back navigation only works with the ```ViewPagerContainerFragment```'s ```NavController```\n\n2. How to use back navigation with ```OnBackPressedCallback```, there is an alternative and more simple way\n    to handle back navigation for ```ViewPager2``` but this also a way to keep in mind if more customization is required.\n    If you do not handle back navigation Activity's back press gets called and application starts from onCreate.\n\n3. Checking out memory leaks with data binding, ViewPager2 adapter and lifecylce.\n     * You should set **data binding** to **null** or you will get memory leaks for this ViewPager2 which is itself also inside a fragment\n\n     * You should set ViePager2's adapter to null in ```onDestroyView```\n\n     * 🔥 You should use ```ChildFragmentStateAdapter(fragmentManager: FragmentManager, lifecycle: Lifecycle)```, not\n     the one that takes ```Fragment``` as parameter.\n     And use **view's lifecycle** instead of setting Fragment's lifecycle.\n\n     ```\n     viewPager.adapter =\n                        ChildFragmentStateAdapter(childFragmentManager, viewLifecycleOwner.lifecycle)\n     ```\n\nRefer to this [stackoverflow question](https://stackoverflow.com/questions/61779776/leak-canary-detects-memory-leaks-for-tablayout-with-viewpager2) for more details.\n\n### [Tutorial6-3NavigationUI-ViewPager2-Appbar-NestedNavigation-LiveData](https://github.com/SmartToolFactory/NavigationComponents-Tutorials/tree/master/Tutorial6-3NavigationUI-ViewPager2-Appbar-NestedNavigation-LiveData)\n\n**Navigation Architecture**\n\n```\n MainActivity(Appbar + Toolbar + TabLayout + ViewPager2)\n   |\n   |- HomeNavHostFragment\n   |  |- HF1 -\u003e HF2 -\u003e HF3\n   |\n   |- DashboardNavHostFragment\n   |  |- DF1 -\u003e DF2 -\u003e DF3\n   |\n   |- NotificationHostFragment\n      |- NF1 -\u003e NF2 -\u003e NF3\n```\n\nIn this tutorial  MainActivity has it's appbar that navigation is controlled using the ```NavController``` retrieved from ```NavHostFragment```  via  ```LiveData```\n\n\u003cp align=\"center\"\u003e\n    \u003cimg src=\"./screenshots/Tutorial6-3.gif\"/\u003e\n\u003c/p\u003e\n\n### Note\n\nThere is an issue with rotation, when device rotated ``` ActivityFragmentStateAdapter.createFragment```  method is not called and it's not possible to access ```NavController``` of newly created fragments. If you do not wish to have a rotatable app\nyou can use live data or ViewModel to get current ```NavController``` to change appbar title and get other\nproperties of ```NavController```. LiveData is observed in ```MainActivity``` to set appbar title\n\n\n### [Tutorial6-4NavigationUI-ViewPager2-FragmentToolbar-NestedNavigation](https://github.com/SmartToolFactory/NavigationComponents-Tutorials/tree/master/Tutorial6-4NavigationUI-ViewPager2-FragmentToolbar-NestedNavigation)\n\n **Navigation Architecture**\n\n ```\n  MainActivity\n     |- MainNavHost\n        |\n        |- ViewPagerContainerFragment(ViewPager)\n            |\n            |- HomeNavHostFragment(Appbar + Toolbar)\n            |  |- HF1 -\u003e HF2 -\u003e HF3\n            |\n            |- DashboardNavHostFragment(Appbar Toolbar)\n            |  |- DF1 -\u003e DF2 -\u003e DF3\n            |\n            |- NotificationHostFragment(Appbar Toolbar)\n               |- NF1 -\u003e NF2 -\u003e NF3\n\n ```\n\nIn this tutorial each ```NavHostFragment``` has it's own toolbar\n They can navigate back with back arrow when navigated to an inner/nested fragment in pages of ViewPager\n\n\u003cp align=\"center\"\u003e\n    \u003cimg src=\"./screenshots/Tutorial6-4.gif\"/\u003e\n\u003c/p\u003e\n\n Using ```FragmentStateAdapter.registerFragmentTransactionCallback``` with ```FragmentStateAdapter``` solves back navigation instead of using ```OnBackPressedCallback.handleOnBackPressed``` in every ```NavHostFragment``` as answered [here](https://stackoverflow.com/a/62629996/5457853)\n\n ```\n init {\n     // Add a FragmentTransactionCallback to handle changing\n     // the primary navigation fragment\n     registerFragmentTransactionCallback(object : FragmentTransactionCallback() {\n         override fun onFragmentMaxLifecyclePreUpdated(\n             fragment: Fragment,\n             maxLifecycleState: Lifecycle.State\n         ) = if (maxLifecycleState == Lifecycle.State.RESUMED) {\n\n             // This fragment is becoming the active Fragment - set it to\n             // the primary navigation fragment in the OnPostEventListener\n             OnPostEventListener {\n                 fragment.parentFragmentManager.commitNow {\n                     setPrimaryNavigationFragment(fragment)\n                 }\n             }\n\n         } else {\n             super.onFragmentMaxLifecyclePreUpdated(fragment, maxLifecycleState)\n         }\n     })\n }\n```\n\nIf defaultNavHost is not set to true true for any ```NavHostFragments```  by setting  ```app:defaultNavHost=\"true\"``` in xml or programmatically\nsnippet above will not work.\n\n### [Tutorial6-5NavigationUI-ViewPager2-FragmentToolbar-MixedNavigation](https://github.com/SmartToolFactory/NavigationComponents-Tutorials/tree/master/Tutorial6-5NavigationUI-ViewPager2-FragmentToolbar-MixedNavigation)\n\n **Navigation Architecture**\n\n ```\n MainActivity\n    |- MainNavHost\n       |\n       |- ParenNavHost((Appbar + Toolbar)\n           |\n           |- ViewPagerContainerFragment(ViewPager2)\n           |   |\n           |   |- HomeNavHostFragment(Appbar + Toolbar)\n           |   |  |- HF1 -\u003e HF2 -\u003e HF3\n           |   |\n           |   |- DashboardNavHostFragment(Appbar + Toolbar)\n           |   |  |- DF1 -\u003e DF2 -\u003e DF3\n           |   |\n           |   |- NotificationHostFragment(Appbar + Toolbar)\n           |   |  |- NF1 -\u003e NF2 -\u003e NF3\n           |   |\n           |   |-LoginFragment1\n           |\n           |- LoginFragment1 -\u003e LoginFragment2\n\n ```\n\nIn this tutorial each ```NavHostFragment``` has it's own toolbar, also ```ParentNavHostFragment``` has it's own toolbar either.\n\n\u003cp align=\"center\"\u003e\n    \u003cimg src=\"./screenshots/Tutorial6-5.gif\"/\u003e\n\u003c/p\u003e\n\nLoginFragment2 in this example is added to  back stack of ParentNavHostFragment because of that it does not have any association with toolbar in  ```ViewPagerContainerFragment```\n\nParentNavHostFragment's role is to have it's own Appbar to contain login fragments and navigate through them using Appbar. Without ```ParentNavHostFragment``` we navigate to ```LoginFragment2``` that has no Appbar.\n\nVisibility of ```ParentNavHostFragment``` is changed via liveData of ```AppbarViewModel```\n\n However, there is an issue whenever Toolbar that is not belong to fragments appear or disappear.\n\n\n### [Tutorial6-6NavigationUI-ViewPager2-Appbar-MixedNavigation-ViewModel](https://github.com/SmartToolFactory/NavigationComponents-Tutorials/tree/master/Tutorial6-6NavigationUI-ViewPager2-Appbar-MixedNavigation-ViewModel)\n\n**Navigation Architecture**\n\n  ```\n MainActivity\n    |- MainNavHostFragment\n       |\n       |- ParenNavHostFragment(Appbar + Toolbar) Here because we wish to have toolbar inside Fragment\n           |\n           |- ViewPagerContainerFragment(TabLayout + ViewPager2)\n           |   |\n           |   |- HomeNavHostFragment\n           |   |  |- HF1 -\u003e HF2 -\u003e HF3\n           |   |\n           |   |- DashboardNavHostFragment\n           |   |  |- DF1 -\u003e DF2 -\u003e DF3\n           |   |\n           |   |- NotificationHostFragment\n           |   |  |- NF1 -\u003e NF2 -\u003e NF3\n           |   |\n           |   |-LoginFragment1\n           |\n           |- LoginFragment1 -\u003e LoginFragment2\n\n  ```\n\nIn this tutorial, only ```ParentNavHostFragment``` has Appbar and Toolbar. Navigation of individual\nNavHostFragments is done via LiveData belong to ```AppbarViewModel.currentNavController``` which\nreturns ```NavController``` of current ```NavHostFragment``` on screen due. Current ```NavController``` is set ```onResume``` to make sure to\nset it only when the current fragment is visible, it's instead of checking if fragment is on screen and visible.\n\n\u003cp align=\"center\"\u003e\n    \u003cimg src=\"./screenshots/Tutorial6-6.gif\"/\u003e\n\u003c/p\u003e\n\n```ParentNavHostFragment```'s role is to have it's own Appbar to contain login fragments and navigate through them using Appbar. Without ParentNavHostFragment we navigate to ```LoginFragment2``` that has no Appbar if it's inside ```ViewPagerContainerFragment```.\n\nIt can be done by putting Appbar to ```MainActivity``` but purpose here is to put\n Appbar + Toolbar inside a fragment to be able to use with ```BottomNavigationView``` for instance\n\n\n\n### [Tutorial7-1BNV-ViewPager2-NestedNavigation](https://github.com/SmartToolFactory/NavigationComponents-Tutorials/tree/master/Tutorial7-1BNV-ViewPager2-NestedNavigation)\n\n**Navigation Architecture**\n\n  ```\n   MainActivity(BottomNavigationView + ViewPager2 + Appbar + Toolbar)\n         |- HomeNavHostFragment\n         |   |- HF1 -\u003e HF2 -\u003e HF3\n         |\n         |- DashboardNavHostFragment\n         |   |- DF1 -\u003e DF2 -\u003e DF3\n         |\n         |- NotificationHostFragment\n         |   |- NF1 -\u003e NF2 -\u003e NF3\n\n  ```\n\nIn this example ```BottomNavigationView``` selects which page of ```ViewPager2``` should be opened using\n```BottomNavigationView.setOnNavigationItemSelectedListener```\n\n\u003cp align=\"center\"\u003e\n    \u003cimg src=\"./screenshots/Tutorial7-1.gif\"/\u003e\n\u003c/p\u003e\n\nAppbar title is changed using  LiveData ```AppbarViewModel.currentNavController``` of visible ```NavHostFragment```  on screen of ViePager2 page\n\n\n\nChange current nav controller to set appbar title\n\n```\nappbarViewModel.currentNavController.observe(this, Observer { it -\u003e\n\n    it?.let { event: Event\u003cNavController\u003e -\u003e\n        event.getContentIfNotHandled()?.let { navController -\u003e\n            val appBarConfig = AppBarConfiguration(navController.graph)\n            dataBinding.toolbar.setupWithNavController(navController, appBarConfig)\n        }\n    }\n})\n\n```\n\n### [Tutorial7-2BNV-ViewPager2-ComplexArchitecture](https://github.com/SmartToolFactory/NavigationComponents-Tutorials/tree/master/Tutorial7-2BNV-ViewPager2-ComplexArchitecture)\n\n**Navigation Architecture**\n\n  ```\n       MainActivity(BottomNavigationView + ViewPager2 + Appbar + Toolbar)\n          |\n          |- ViewPagerContainerFragment(TabLayout + ViewPager2)\n          |      |\n          |      |- HomeNavHostFragment\n          |      |  |- HF1 -\u003e HF2 -\u003e HF3\n          |      |\n          |      |- DashboardNavHostFragment\n          |      |  |- DF1 -\u003e DF2 -\u003e DF3\n          |      |\n          |      |- NotificationHostFragment\n          |      |  |- NF1 -\u003e NF2 -\u003e NF3\n          |      |\n          |      |-LoginFragment1\n          |\n          |- DashboardNavHostFragment\n          |   |- DF1 -\u003e DF2 -\u003e DF3\n          |\n          |- NotificationHostFragment\n          |   |- NF1 -\u003e NF2 -\u003e NF3\n  ```\n\nThis example is combination of Tutorial6-6 and Tutorial 7-1\n\n\n\u003cp align=\"center\"\u003e\n    \u003cimg src=\"./screenshots/Tutorial7-2.gif\"/\u003e\n\u003c/p\u003e\n\n First tab of the ```BottomNavigationView``` is ```ViewPagerContainerFragment``` which has a ```ViewPager2``` that has it's own pages with each it's own back stack setting ```NavController``` is done both using ```AppbarViewModel``` and ```BottomNavigationView.setupWithNavController``` in the NavigationExtensions code for setting BottomNavigationView back stack.\n\n\n### [Tutorial7-3BNV-ViewPager2-FragmentToolbar-MixedNavigation](https://github.com/SmartToolFactory/NavigationComponents-Tutorials/tree/master/Tutorial7-3BNV-ViewPager2-FragmentToolbar-MixedNavigation)\n\n**Navigation Architecture**\n\n  ```\n    MainActivity\n      |- MainNavHostFragment\n           |\n           |- ContainerNavHostFragment(BottomNavigationView  Appbar + Toolbar)\n           |    |\n           |    |- ViewPagerContainerFragment(ViewPager2 + TabLayout)\n           |    |      |\n           |    |      |- PostVerticalNavHost\n           |    |      |  |- PostVerticalFragment -\u003e PostDetailFragment\n           |    |      |\n           |    |      |- PostHorizontalNavHost\n           |    |      |  |- PostHorizontalFragment -\u003e PostDetailFragment\n           |    |      |\n           |    |      |- PostGridNavHostFragment\n           |    |      |  |- PostGridFragment\n           |    |      |\n           |    |      |- PostStaggerNavHostFragment\n           |    |      |  |- PostStaggeredFragment\n           |    |      |\n           |    |      |- NotificationHostFragment\n           |    |      |  |- NF1 -\u003e NF2 -\u003e NF3\n           |    |      |\n           |    |      |- LoginFragment1\n           |    |\n           |    |\n           |    |- DashboardNavHostFragment\n           |    |   |- DF1 -\u003e DF2 -\u003e DF3\n           |    |\n           |    |- NotificationHostFragment\n           |    |  |- NF1 -\u003e NF2 -\u003e NF3\n           |    |\n           |    |- \u0026PostGridFragment -\u003e PostDetailFragment\n           |    |\n           |    |- \u0026LoginFragment1 -\u003e LoginFragment2\n           |\n           |\n           |- \u0026PostStaggeredFragment -\u003e PostDetailFragment\n  ```\n\nIn this tutorial ```BottomNavigationView``` is inside ```MainFragment```. ```MainActivity``` can navigate to a different fragment other than the ```MainFragment``` using nav_graph main destinations.\n\n\u003cp align=\"center\"\u003e\n  \u003cimg src=\"./screenshots/Tutorial7-3.gif\"/\u003e\n\u003c/p\u003e\n\n Navigation is layered, fragments annotated with **\u0026** display that hey navigate at that level, not actually added to that hierarchy.\n\n For instance, ```PostStaggeredFragment``` which is in ```ViewPager2``` calls snippet below to get main ```NavController``` to navigate in main navigation graph\n ```requireActivity().findNavController(R.id.main_nav_host_fragment).navigate(R.id.action_mainFragment_to_postDetailFragment, bundle)```\n\n```PostGridFragment``` which is in ```ViewPager2``` gets ```PNavController```P that belong to ```ViewPagerContainerFragment``` via ```parentFragment?.parentFragment?.findNavController()``` and navigates from ```ViewPagerContainerFragment``` to ```PostDetailFragment```\n\n### 🔥🔥🔥 Important\n\nIf you navigate from ```PostStaggeredFragment``` to ```PostDetailFragment``` fragment you will see that memory leak occurs. It happens due to BottomNavigationView.setupWithNavController``` function in ```NavigationExtensions.kt``` class leaking because of listeners not being unregistered in extension functions in ```onDestroyView``` of fragment.\n\nCheck out Tutorial8-2 for solution for this issue\n\n### [Tutorial8-1DynamicFeatures-Navigation](https://github.com/SmartToolFactory/NavigationComponents-Tutorials/tree/master/Tutorial8-1DynamicFeatures-Navigation)\n\nThis tutorial to navigate to dynamic feature module from App, navigate from dynamic feature module  gallery to favorites.\n\n\u003cp align=\"center\"\u003e\n  \u003cimg src=\"./screenshots/Tutorial8-1.gif\"/\u003e\n\u003c/p\u003e\n\nSteps to create dynamic navigation from app to dynamic feature modules, or from one dynamic feature module to another\n\n1. Replace  ```android:name=\"androidx.navigation.fragment.NavHostFragment\"``` with ```android:name=\"androidx.navigation.dynamicfeatures.fragment.DynamicNavHostFragment\"``` for the layouts\n```\n\u003candroidx.fragment.app.FragmentContainerView\n    android:id=\"@+id/nestedDashboardNavHostFragment\"\n    android:name=\"androidx.navigation.dynamicfeatures.fragment.DynamicNavHostFragment\"\n    app:defaultNavHost=\"true\"\n    app:navGraph=\"@navigation/nav_graph_dashboard\"/\u003e\n```\n\n2. Add dynamic navigation with ```\u003cinclude\u003e```, ```\u003cactivity\u003e``` or as fragmentt to any navigation graph\n    * You don't have to use an id, but if you do, same id defined here must be used in dynamic feature module, or will get an error.\n    * Add package name of dynamic feature module\n    * Add nav graph name in navigation folder of dynamic feature module\n    * Add module name which is also in app's build.gradle file\n    * Optionally add arguments to pass to dynamic feature module fragments\n\n ```\n \u003c!-- gallery dynamic feature module--\u003e\n \u003cinclude-dynamic\n     android:id=\"@+id/nav_graph_gallery\"\n     android:name=\"com.smarttoolfactory.gallery\"\n     app:graphResName=\"nav_graph_gallery\"\n     app:moduleName=\"gallery\"\u003e\n     \u003cargument\n         android:name=\"count\"\n         android:defaultValue=\"0\"\n         app:argType=\"integer\" /\u003e\n \u003c/include-dynamic\u003e\n ```\n\n3. In dynamic feature module navigation creata navigation graph to navigate in feature module fragmnent or navigate to other dynamic feature modueles, and passing arguments and getting the result from a fragment with ```savedStateHandle```.\n    * id in dynamic feature module should not contain **+**, because you are using the same id resource defined in app or the snippet above. If you do you will have the error i got [here](https://stackoverflow.com/questions/62704720/dynamic-feature-module-navigation-illegalstateexception-the-included-navigatio)\n\n ```\n \u003c?xml version=\"1.0\" encoding=\"utf-8\"?\u003e\n \u003cnavigation xmlns:android=\"http://schemas.android.com/apk/res/android\"\n     xmlns:app=\"http://schemas.android.com/apk/res-auto\"\n     android:id=\"@id/nav_graph_gallery\"\n     app:moduleName=\"gallery\"\n     app:startDestination=\"@id/galleryFragment1\"\u003e\n\n     \u003cfragment\n         android:id=\"@+id/galleryFragment1\"\n         android:name=\"com.smarttoolfactory.gallery.GalleryFragment1\"\n         android:label=\"GalleryFragment1\"\u003e\n         \u003caction\n             android:id=\"@+id/action_galleryFragment1_to_galleryFragment2\"\n             app:destination=\"@id/galleryFragment2\" /\u003e\n         \u003caction\n             android:id=\"@+id/action_galleryFragment1_to_nav_graph_favorites\"\n             app:destination=\"@id/nav_graph_favorites\" /\u003e\n     \u003c/fragment\u003e\n\n     \u003c!-- favorite dynamic feature module--\u003e\n     \u003cinclude-dynamic\n         android:id=\"@id/nav_graph_favorites\"\n         android:name=\"com.smarttoolfactory.favorites\"\n         app:graphResName=\"nav_graph_favorites\"\n         app:moduleName=\"favorites\" \u003e\n         \u003cargument\n             android:name=\"count\"\n             app:argType=\"integer\"\n             android:defaultValue=\"0\" /\u003e\n     \u003c/include-dynamic\u003e\n \u003c/navigation\u003e\n\n ```\n\n```HomeFragment1``` listen ```savedStateHandle``` with ```findNavController().currentBackStackEntry?.savedStateHandle.getLiveData\u003cInt\u003e```\n\n```HomeFragment2``` and GalleryFragment sets result with ```findNavController().previousBackStackEntry?.savedStateHandle?.set(\"count\", count)```\n\n### [Tutorial8-2DynamicFeatures-ComplexArchitecture](https://github.com/SmartToolFactory/NavigationComponents-Tutorials/tree/master/Tutorial8-2DynamicFeatures-ComplexArchitecture)\n\n**Navigation Architecture**\n\n  ```\n    MainActivity\n      |- MainNavHostFragment\n           |\n           |- ContainerNavHostFragment(BottomNavigationView  Appbar + Toolbar)\n           |    |\n           |    |- ViewPagerContainerFragment(ViewPager2 + TabLayout)\n           |    |      |\n           |    |      |- PostVerticalNavHost\n           |    |      |  |- PostVerticalFragment -\u003e PostDetailFragment\n           |    |      |\n           |    |      |- PostHorizontalNavHost\n           |    |      |  |- PostHorizontalFragment -\u003e PostDetailFragment\n           |    |      |\n           |    |      |- PostGridNavHostFragment\n           |    |      |  |- PostGridFragment\n           |    |      |\n           |    |      |- PostStaggerNavHostFragment\n           |    |      |  |- PostStaggeredFragment\n           |    |      |\n           |    |      |- NotificationHostFragment\n           |    |      |  |- NF1 -\u003e NF2 -\u003e NF3\n           |    |      |\n           |    |      |- LoginFragment1\n           |    |\n           |    |\n           |    |- DashboardNavHostFragment\n           |    |   |- DF1 -\u003e DF2 -\u003e DF3\n           |    |\n           |    |- NotificationHostFragment\n           |    |  |- NF1 -\u003e NF2 -\u003e NF3\n           |    |\n           |    |- \u0026PostGridFragment -\u003e PostDetailFragment\n           |    |\n           |    |- \u0026LoginFragment1 -\u003e LoginFragment2\n           |    |\n           |    |- NF1 | 2F2 -\u003e Camera Dynamic Feature\n           |\n           |\n           |- DF1 | 2F2 -\u003e Photo Dynamic Feature\n           |\n           |- NF1 | 2F2 -\u003e Camera Dynamic Feature\n           |\n           |- \u0026PostStaggeredFragment -\u003e PostDetailFragment\n\n           // Photos Dynamic feature navigate to Camera Dynamic feature\n           |- Photos Dynamic Feature -\u003e Camera Dynamic Feature\n  ```\n\nIn this tutorial same as Tutorial 7-3 navigation layered, and navigation from app module to dynamic features, or navigation from ```Photos``` dynamic feature module\nto ```Camera``` dynamic feature module is available.\n\n\u003cp align=\"center\"\u003e\n  \u003cimg src=\"./screenshots/Tutorial8-2.gif\"/\u003e\n\u003c/p\u003e\n\nThere are two versions of main fragment.\n\n One with ```MainFragment``` which uses ```BottomNavigationView``` extension, and ```MainFragmentWithViewPager``` uses ```ViewPager2``` to create back stack of ```BottomNavigationView```.\n\n### Note\n\n🔥 Since ```DynamicNavHostFragment``` used instead of ```NavHostFragment``` another extension should be written that creates fragments that have [DynamicNavHostFragment] in fragments.\n\nIf  ```BottomNavigationView``` extension is used with ```DynamicNavHostFragment``` it returns the error below\n\u003e       Caused by: java.lang.IllegalStateException: Could not find Navigator with name \"include-dynamic\". You must call NavController.addNavigator() for each navigation type.\n\u003e          at androidx.navigation.NavigatorProvider.getNavigator(NavigatorProvider.java:98)\n\u003e          at androidx.navigation.NavInflater.inflate(NavInflater.java:107)\n\u003e          at androidx.navigation.NavInflater.inflate(NavInflater.java:141)\n\u003e          at androidx.navigation.NavInflater.inflate(NavInflater.java:88)\n\nAlso, since extension is not used, observe that not getting  **MEMORY LEAK** that was present in Tutorial7-3\n\n### ToDos:\n- [ ] Use nav graph ViewModel by navGraphViewModels, couldn't find it yet\n- [ ] Solve ```setFragmentResultListener``` issue to get result from a framgent on back press, and use instead of savedStateHandle\n- [ ] Use saveStateHandle or save fragment state in Tutorial 8-2 when ViewPager2 moves away from viewPort\n- [ ] There is a performance issue in Tutorial 8-2 when navigate back from StaggerPostListFragment, or navigating back to fragment main\n- [ ] Use BottomNavigationView extension with ```DynamicNavHostFragment```, or create another extension for dynamic feature modules\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsmarttoolfactory%2Fnavigationcomponents-tutorials","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fsmarttoolfactory%2Fnavigationcomponents-tutorials","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsmarttoolfactory%2Fnavigationcomponents-tutorials/lists"}