使用Navigation架构组件时,点击返回键如何避免Fragment重建?
我之前也碰到过这个头疼的问题——Navigation组件默认用replace来切换Fragment,这会导致前一个Fragment被销毁,返回时不得不重新创建实例。要实现类似原生add的效果(保留Fragment实例不销毁),我们可以通过自定义Navigator来修改这个默认行为,下面是具体步骤:
1. 自定义FragmentNavigator
创建一个继承自FragmentNavigator的类,重写navigate方法,把默认的replace操作改成add,同时设置主导航Fragment来保证交互逻辑正常:
class AddFragmentNavigator( context: Context, fragmentManager: FragmentManager, containerId: Int ) : FragmentNavigator(context, fragmentManager, containerId) { override fun navigate( entries: List<NavBackStackEntry>, navOptions: NavOptions?, navigatorExtras: Navigator.Extras? ) { val ft = fragmentManager.beginTransaction() var isAdded = false for (entry in entries) { val fragment = createFragment(entry) // 用add替代replace,保留之前的Fragment实例 ft.add(containerId, fragment, entry.id) // 设置当前Fragment为主导航Fragment,保证交互焦点正确 ft.setPrimaryNavigationFragment(fragment) isAdded = true } if (isAdded) { ft.commit() } } }
2. 自定义NavHostFragment
创建自定义的NavHostFragment,让它返回我们刚才写的AddFragmentNavigator,替换掉默认的导航逻辑:
class AddNavHostFragment : NavHostFragment() { override fun createFragmentNavigator(): Navigator<out NavDestination> { return AddFragmentNavigator( requireContext(), childFragmentManager, getContainerId() ) } private fun getContainerId(): Int { val id = id return if (id != 0 && id != View.NO_ID) id else android.R.id.content } }
3. 修改布局中的NavHost
把布局里默认的NavHostFragment替换成我们自定义的类(注意替换成你的实际包路径):
<androidx.fragment.app.FragmentContainerView android:id="@+id/nav_host_fragment" android:name="com.yourpackage.AddNavHostFragment" android:layout_width="match_parent" android:layout_height="match_parent" app:navGraph="@navigation/nav_graph" />
这样修改后,当你从Fragment1跳转到Fragment2时,Fragment1不会被销毁,只是被隐藏;点击返回键时,Fragment2会被移除,Fragment1直接显示,完全不会触发重建。
另外,如果你的核心需求只是避免数据丢失(不需要完全保留Fragment实例),也可以用ViewModel来存储Fragment1的业务数据——即使Fragment重建,ViewModel的实例会被保留,数据也不会丢失,这也是Navigation组件官方推荐的状态保存方式:
class Fragment1ViewModel : ViewModel() { // 在这里存储你的数据,比如LiveData或者普通变量 val userData = MutableLiveData<String>() } // 在Fragment1中获取ViewModel val viewModel = ViewModelProvider(this)[Fragment1ViewModel::class.java]
内容的提问来源于stack exchange,提问作者user6667443
相关产品推荐
相关产品推荐

