When navigation returns, it will re-create the version of the fragment before 2.3.5, most of the modifications (the new version is invalid):
override fun navigate( destination: Destination, args: Bundle?, navOptions: NavOptions?, navigatorExtras: Navigator.Extras? ): NavDestination? { if (mFragmentManager.isStateSaved) { Log.i( TAG, "Ignoring navigate() call: FragmentManager has already" + "saved its state" ) return null } var className = destination.className if (className[0] == '.') { className = mContext.packageName + className } //final Fragment frag = instantiateFragment(mContext, mManager, // className, args); //frag.setArguments(args); val ft = mFragmentManager.beginTransaction() var enterAnim = navOptions?.enterAnim ?: -1 var exitAnim = navOptions?.exitAnim ?: -1 var popEnterAnim = navOptions?.popEnterAnim ?: -1 var popExitAnim = navOptions?.popExitAnim ?: -1 if (enterAnim != -1 || exitAnim != -1 || popEnterAnim != -1 || popExitAnim != -1) { enterAnim = if (enterAnim != -1) enterAnim else 0 exitAnim = if (exitAnim != -1) exitAnim else 0 popEnterAnim = if (popEnterAnim != -1) popEnterAnim else 0 popExitAnim = if (popExitAnim != -1) popExitAnim else 0 ft.setCustomAnimations(enterAnim, exitAnim, popEnterAnim, popExitAnim) } val fragment = mFragmentManager.primaryNavigationFragment if (fragment != null) { ft.setMaxLifecycle(fragment, Lifecycle.State.STARTED) ft.hide(fragment) } var fragment: Fragment? = null val tag = destination.id.toString() frag = mFragmentManager.findFragmentByTag(tag) if (frag != null) { ft.setMaxLifecycle(frag, Lifecycle.State.RESUMED) ft.show(frag) } else { frag = instantiateFragment(mContext, mFragmentManager, className, args) frag.arguments = args ft.add(mContainerId, fragment, tag) } //ft.replace(mContainerId, frag); ft.setPrimaryNavigationFragment(frag) @IdRes val destId = destination.id var mBackStack: ArrayDeque<Int>? = null try { val field = FragmentNavigator::class.java.getDeclaredField("mBackStack") field.isAccessible = true mBackStack = field[this] as ArrayDeque<Int> } catch (e: NoSuchFieldException) { e.printStackTrace() } catch (e: IllegalAccessException) { e.printStackTrace() } val initialNavigation = mBackStack!!.isEmpty() // TODO Build first class singleTop behavior for fragments val isSingleTopReplacement = (navOptions != null & amp; & amp; !initialNavigation & amp; & amp; navOptions.shouldLaunchSingleTop() & amp; & amp; mBackStack.peekLast() == destId) val isAdded: Boolean isAdded = if (initialNavigation) { true } else if (isSingleTopReplacement) { // Single Top means we only want one instance on the back stack if (mBackStack.size > 1) { // If the Fragment to be replaced is on the FragmentManager's // back stack, a simple replace() isn't enough so we // remove it from the back stack and put our replacement // on the back stack in its place mFragmentManager.popBackStack( generateBackStackName(mBackStack.size, mBackStack.peekLast()), FragmentManager.POP_BACK_STACK_INCLUSIVE ) ft.addToBackStack(generateBackStackName(mBackStack.size, destId)) } false } else { ft.addToBackStack(generateBackStackName(mBackStack.size + 1, destId)) true } if (navigatorExtras is Extras) { for ((key, value) in navigatorExtras.sharedElements) { ft.addSharedElement(key!!, value!!) } } ft.setReorderingAllowed(true) ft.commit() // The commit succeeded, update our view of the world return if (isAdded) { mBackStack.add(destId) destination } else { null } }
In higher versions of navigation (greater than 2.4.0), the FragmentNavigator class is rewritten, so the above method is invalid.
The modification method of the new version is provided for reference (only version 2.5.3 was tested):
@Navigator.Name("fragment") class FragmentNavigatorHideShow( private val context: Context, private val fragmentManager: FragmentManager, private val containerId: Int ) : FragmentNavigator(context, fragmentManager, containerId) { override fun navigate( entries: List<NavBackStackEntry>, navOptions: NavOptions?, navigatorExtras: Navigator.Extras? ) { if (fragmentManager.isStateSaved) { Log.i( TAG, "Ignoring navigate() call: FragmentManager has already saved its state" ) return } for (entry in entries) { navigateOver(entry, navOptions, navigatorExtras) } } private fun navigateOver( entry: NavBackStackEntry, navOptions: NavOptions?, navigatorExtras: Navigator.Extras? ) { //*************Differences between the previous and later versions*initialNavigation****** val initialNavigation = state.backStack.value.isEmpty() val backStack = state.backStack.value val destination = entry.destination as Destination @IdRes val destId = destination.id var mBackStack: LinkedHashSet<String>?= null try { //***********Differences between the before and after versions*The variables obtained by reflection are different****** val field = FragmentNavigator::class.java.getDeclaredField("savedIds") field.isAccessible = true mBackStack = field[this] as LinkedHashSet<String> } catch (e: NoSuchFieldException) { e.printStackTrace() } catch (e: IllegalAccessException) { e.printStackTrace() } val restoreState = ( navOptions != null & amp; & amp; !initialNavigation & amp; & amp; navOptions.shouldRestoreState() & amp; & amp; mBackStack!!.remove(entry.id)//****************Differences between the before and after versions*mBackStack uses the reflection value****** ) if (restoreState) { // Restore back stack does all the work to restore the entry fragmentManager.restoreBackStack(entry.id) state.push(entry) return } val ft = createFragmentTransactionOver(entry, navOptions) // TODO Build first class singleTop behavior for fragments val isSingleTopReplacement = ( navOptions != null & amp; & amp; !initialNavigation & amp; & amp; navOptions.shouldLaunchSingleTop() & amp; & amp; backStack.last().destination.id == destId ) val isAdded = when { initialNavigation -> { true } isSingleTopReplacement -> { // Single Top means we only want one instance on the back stack if (backStack. size > 1) { // If the Fragment to be replaced is on the FragmentManager's // back stack, a simple replace() isn't enough so we // remove it from the back stack and put our replacement // on the back stack in its place fragmentManager.popBackStack( entry.id, FragmentManager.POP_BACK_STACK_INCLUSIVE ) ft.addToBackStack(entry.id) } false } else -> { ft.addToBackStack(entry.id) true } } // if (!initialNavigation) { // ft.addToBackStack(entry.id) // } if (navigatorExtras is Extras) { for ((key, value) in navigatorExtras.sharedElements) { ft.addSharedElement(key, value) } } ft.commit() // The commit succeeded, update our view of the world if(isAdded) state.push(entry) } private fun createFragmentTransactionOver( entry: NavBackStackEntry, navOptions: NavOptions? ): FragmentTransaction { val destination = entry.destination as Destination val args = entry.arguments var className = destination.className if (className[0] == '.') { className = context.packageName + className } // val frag = fragmentManager.fragmentFactory.instantiate(context.classLoader, className) // frag.arguments = args val ft = fragmentManager.beginTransaction() var enterAnim = navOptions?.enterAnim ?: -1 var exitAnim = navOptions?.exitAnim ?: -1 var popEnterAnim = navOptions?.popEnterAnim ?: -1 var popExitAnim = navOptions?.popExitAnim ?: -1 if (enterAnim != -1 || exitAnim != -1 || popEnterAnim != -1 || popExitAnim != -1) { enterAnim = if (enterAnim != -1) enterAnim else 0 exitAnim = if (exitAnim != -1) exitAnim else 0 popEnterAnim = if (popEnterAnim != -1) popEnterAnim else 0 popExitAnim = if (popExitAnim != -1) popExitAnim else 0 ft.setCustomAnimations(enterAnim, exitAnim, popEnterAnim, popExitAnim) } val fragment = fragmentManager.primaryNavigationFragment if (fragment != null) { ft.setMaxLifecycle(fragment, Lifecycle.State.STARTED) ft.hide(fragment) } var fragment: Fragment? = null val tag = destination.id.toString() frag = fragmentManager.findFragmentByTag(tag) if (frag != null) { ft.setMaxLifecycle(frag, Lifecycle.State.RESUMED) ft.show(frag) } else { frag = instantiateFragment(context, fragmentManager, className, args) frag.arguments = args ft.add(containerId, fragment, tag) } // ft.replace(containerId, frag) ft.setPrimaryNavigationFragment(frag) ft.setReorderingAllowed(true) return ft } }
These three method calls can be integrated into the for loop of the first method. You can see the modification points by comparing them here.
This modification is temporarily sufficient and the fragment will not be re-created when returning.