Is there a way to keep fragment alive when using BottomNavigationView with new NavController?
Try this.
Navigator
Create custom navigator.
@Navigator.Name("custom_fragment") // Use as custom tag at navigation.xml
class CustomNavigator(
private val context: Context,
private val manager: FragmentManager,
private val containerId: Int
) : FragmentNavigator(context, manager, containerId) {
override fun navigate(destination: Destination, args: Bundle?, navOptions: NavOptions?) {
val tag = destination.id.toString()
val transaction = manager.beginTransaction()
val currentFragment = manager.primaryNavigationFragment
if (currentFragment != null) {
transaction.detach(currentFragment)
}
var fragment = manager.findFragmentByTag(tag)
if (fragment == null) {
fragment = destination.createFragment(args)
transaction.add(containerId, fragment, tag)
} else {
transaction.attach(fragment)
}
transaction.setPrimaryNavigationFragment(fragment)
transaction.setReorderingAllowed(true)
transaction.commit()
dispatchOnNavigatorNavigated(destination.id, BACK_STACK_DESTINATION_ADDED)
}
}
NavHostFragment
Create custom NavHostFragment.
class CustomNavHostFragment: NavHostFragment() {
override fun onCreateNavController(navController: NavController) {
super.onCreateNavController(navController)
navController.navigatorProvider += PersistentNavigator(context!!, childFragmentManager, id)
}
}
navigation.xml
Use custom tag instead of fragment tag.
<navigation xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto" android:id="@+id/navigation"
app:startDestination="@id/navigation_first">
<custom_fragment
android:id="@+id/navigation_first"
android:name="com.example.sample.FirstFragment"
android:label="FirstFragment" />
<custom_fragment
android:id="@+id/navigation_second"
android:name="com.example.sample.SecondFragment"
android:label="SecondFragment" />
</navigation>
activity layout
Use CustomNavHostFragment instead of NavHostFragment.
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/container"
android:layout_width="match_parent"
android:layout_height="match_parent">
<fragment
android:id="@+id/nav_host_fragment"
android:name="com.example.sample.CustomNavHostFragment"
android:layout_width="0dp"
android:layout_height="0dp"
app:layout_constraintBottom_toTopOf="@+id/bottom_navigation"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:navGraph="@navigation/navigation" />
<com.google.android.material.bottomnavigation.BottomNavigationView
android:id="@+id/bottom_navigation"
android:layout_width="0dp"
android:layout_height="wrap_content"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:menu="@menu/navigation" />
</androidx.constraintlayout.widget.ConstraintLayout>
Update
I created sample project. link
I don't create custom NavHostFragment. I use navController.navigatorProvider += navigator
.
Save state of fragment A when navigating from bottomNavigationView to fragment B
Few facts around Android Navigation Component with Bottom Navigation Bar.
- > Fragments are always recreated (onCreate, onViewCreated, onViewDestroyed are called as soon as the user navigates to another fragment)
- > Fragment will save its state only when activity is recreated (e.g. screen rotation) , navigating between fragments doesn't save fragment's state.
I want to save the state of this fragment (with the text there) when
navigating to another fragment and the coming back to the fragment A
(and have the text still there from the previous button click).
This wont be possible as a new instance of FragmentA is created when
you navigate back from fragmentB to Fragment A.
you can not achieve this with navigation controller as of now.
Since you are using navigation component, You should switch to using Viewmodel to solve retain fragment state issue.
Consult the following link to see how to communicate and save data between fragments using viewmodel.
https://androidwave.com/fragment-communication-using-viewmodel/
Android navigation component: how save fragment state
As per the open issue, Navigation does not directly support multiple back stacks - i.e., saving the state of stack B when you go back to B from A or C since Fragments do not support multiple back stacks.
As per this comment:
The NavigationAdvancedSample is now available at https://github.com/googlesamples/android-architecture-components/tree/master/NavigationAdvancedSample
This sample uses multiple NavHostFragments, one for each bottom navigation tab, to work around the current limitations of the Fragment API in supporting multiple back stacks.
We'll be proceeding with the Fragment API to support multiple back stacks and the Navigation API to plug into it once created, which will remove the need for anything like the
NavigationExtensions.kt
file. We'll continue to use this issue to track that work.
Therefore you can use the NavigationAdvancedSample approach in your app right now and star the issue so that you get updates for when the underlying issue is resolved and direct support is added to Navigation.
BottomNavigationView with navhostfragment not showing fragment, android?
I am not sure what is the issue with the bottom navigation view with this use case. After going through multiple links and posts I was able to solve
You need an extension for bottom navigation which takes up list of nav graphs.
I found that piece in one of the links
Extension
BottomNavigationExt.kt
Your XML will look like
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
xmlns:app="http://schemas.android.com/apk/res-auto"
tools:context="home.HomeFragment">
<androidx.fragment.app.FragmentContainerView
android:id="@+id/homeNavHost"
android:name="androidx.navigation.fragment.NavHostFragment"
android:layout_width="0dp"
android:layout_height="0dp"
app:layout_constraintBottom_toTopOf="@+id/bottomMenu"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<com.google.android.material.bottomnavigation.BottomNavigationView
android:id="@+id/bottomMenu"
android:layout_width="0dp"
android:layout_height="wrap_content"
app:labelVisibilityMode="labeled"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:menu="@menu/bottom_menu" />
</androidx.constraintlayout.widget.ConstraintLayout>
Finally setup with
val navGraphIds = listOf(
R.navigation.dashboard_nav_graph,
R.navigation.offer_nav_graph,
R.navigation.profile_nav_graph,
R.navigation.document_nav_graph,
R.navigation.more_nav_graph
)
// Setup the bottom navigation view with a list of navigation graphs
val controller = binding.bottomMenu.setupWithNavController(
navGraphIds = navGraphIds,
fragmentManager = childFragmentManager,
containerId = R.id.homeNavHost,
intent = requireActivity().intent
)
The most important your menu item id and graph id should be same
Related Topics
Sending Text Messages Programmatically in Android
How to Implement Getfilter() with Custom Adapter That Extends Baseadapter
Get Path of Image from Action_Image_Capture Intent
Unicode Characters Not Displayed in Textview.Settext
Android - File Provider - Permission Denial
Couldn't Locate Lint-Gradle-Api-26.1.2.Jar for Flutter Project
Adb Root Is Not Working on Emulator (Cannot Run as Root in Production Builds)
How to Pause/Resume Thread in Android
Match_Parent Width Does Not Work in Recyclerview
Why Are Most UI Frameworks Single Threaded
Gradle Build Tool Cannot Find Play-Services-Tasks.Aar? Why
How to Implement a View Holder