I am trying to create a side navigation drawer based app using the latest navigation component library ('androidx.navigation:navigation-fragment-ktx:2.5.3'
and 'androidx.navigation:navigation-ui-ktx:2.5.3'
)
I tried to follow the basic template for creating a nav drawer, but everytime i click a menu item, it destroys the current fragment and creates a new one. also, when pressing back, we go back to start fragment, but the start fragment is also recreated, and is not in the state which it originally was.
So my question is if it is possible to retain a fragment without causing a repeated destroy/create cycle ?
I know that the "state" of the fragment can be retained using activity viewmodel or save instance state, but at certain times, it would be more beneficial to just use a singleton fragment instead of recreating it. The following advance navigation sample from google does retain the navigation state, but my current doesn't seem to be even doing that, why?
code:
//navgraph sidenav advance.xml
<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"
app:startDestination="@+id/nav_home">
<navigation android:id="@+id/nav_home" app:startDestination="@+id/frag_home">
<fragment
android:id="@+id/frag_home"
android:name="work.curioustools.fragmentpracticalsamples.side_navigation.HomeFragment"
android:label="@string/menu_home"
tools:layout="@layout/fragment_side_navigation" />
</navigation>
<navigation android:id="@+id/nav_gallery" app:startDestination="@+id/frag_gallary">
<fragment
android:id="@+id/frag_gallary"
android:name="work.curioustools.fragmentpracticalsamples.side_navigation.GalleryFragment"
android:label="@string/menu_gallery"
tools:layout="@layout/fragment_side_navigation" />
</navigation>
<navigation android:id="@+id/nav_slideshow" app:startDestination="@+id/frag_slideshow">
<fragment
android:id="@+id/frag_slideshow"
android:name="work.curioustools.fragmentpracticalsamples.side_navigation.SlideshowFragment"
android:label="@string/menu_slideshow"
tools:layout="@layout/fragment_side_navigation" />
</navigation>
</navigation>
activity sidenav default.xml
<?xml version="1.0" encoding="utf-8"?>
<androidx.drawerlayout.widget.DrawerLayout 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/drawer_layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true"
tools:ignore="ContentDescription"
tools:openDrawer="start">
<androidx.coordinatorlayout.widget.CoordinatorLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<com.google.android.material.appbar.AppBarLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:theme="@style/ThemeOverlay.MaterialComponents.Dark.ActionBar">
<androidx.appcompat.widget.Toolbar
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:background="?attr/colorPrimary"
tools:navigationIcon="@drawable/ic_sidenav"
app:title="@string/app_name"
app:popupTheme="@style/ThemeOverlay.MaterialComponents.Light" />
</com.google.android.material.appbar.AppBarLayout>
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_behavior="@string/appbar_scrolling_view_behavior">
<androidx.fragment.app.FragmentContainerView
android:id="@+id/fragment_navhost_default"
android:name="androidx.navigation.fragment.NavHostFragment"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:defaultNavHost="true"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:navGraph="@navigation/navgraph_sidenav_advance" />
</androidx.constraintlayout.widget.ConstraintLayout>
<com.google.android.material.floatingactionbutton.FloatingActionButton
android:id="@+id/fab"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="bottom|end"
android:layout_margin="16dp"
app:srcCompat="@android:drawable/ic_dialog_email"
/>
</androidx.coordinatorlayout.widget.CoordinatorLayout>
<com.google.android.material.navigation.NavigationView
android:id="@+id/nav_view"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_gravity="start"
android:fitsSystemWindows="true"
tools:layout_width="100dp"
app:menu="@menu/menu_side_navigation" />
</androidx.drawerlayout.widget.DrawerLayout>
// activity : SideNavigationDrawerDefaultActivity
class SideNavigationDrawerDefaultActivity : AppCompatActivity() {
private val binding by lazy { ActivitySideNavigationDefaultBinding.inflate(layoutInflater) }
private val appBarConfiguration by lazy { AppBarConfiguration(setOf(R.id.nav_home, R.id.nav_gallery, R.id.nav_slideshow), binding.drawerLayout) }
private val navController by lazy {
val navHost = supportFragmentManager.findFragmentById(R.id.fragment_navhost_default) as NavHostFragment
navHost.navController
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(binding.root)
//setupActionBar
setSupportActionBar(binding.toolbar)
setupActionBarWithNavController(navController, appBarConfiguration)
//setup side drawer
binding.navView.setupWithNavController(navController)
binding.fab.setOnClickListener { snack("hello",it) }
}
override fun onSupportNavigateUp() = navController.navigateUp(appBarConfiguration) || super.onSupportNavigateUp()
}