如何在navController控制的底部导航菜单场景下保存Fragment的状态
解决方案
针对底部导航切换Fragment、屏幕旋转两种场景下的数据丢失问题,可以根据你的业务需求选择以下几种方案:
1. 使用ViewModel存储业务数据(官方首推,适配两种场景)
该方案可以同时覆盖配置变更(旋转屏幕)、导航切换导致的Fragment销毁重建场景:
- 自定义ViewModel类,将所有需要保留的输入框内容、列表数据、选中状态等业务数据定义为ViewModel的成员变量
- 实例化ViewModel时绑定宿主Activity的生命周期,示例代码:
// Kotlin 示例 val myViewModel = ViewModelProvider(requireActivity())[MyViewModel::class.java]// Java 示例 MyViewModel myViewModel = new ViewModelProvider(requireActivity()).get(MyViewModel.class); - 在Fragment的
onViewCreated生命周期中,直接从ViewModel读取数据回填到对应的布局组件中;用户修改数据时同步更新ViewModel中的对应值 - 注意不要在ViewModel中持有View、Activity等上下文类的引用,避免内存泄漏
2. 配合onSaveInstanceState保存轻量界面状态
该方案适合保存控件滚动位置、输入框焦点、临时选中状态等轻量界面数据,主要适配配置变更场景,如需适配导航切换需要配合Navigation组件的多回退栈配置:
- 重写Fragment的
onSaveInstanceState方法,将需要保存的数据存入Bundle参数:override fun onSaveInstanceState(outState: Bundle) { super.onSaveInstanceState(outState) outState.putString("input_content", binding.editText.text.toString()) outState.putInt("select_position", selectPosition) } - 在
onViewCreated中判断savedInstanceState是否非空,非空时直接读取数据回填:override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) savedInstanceState?.let { binding.editText.setText(it.getString("input_content")) selectPosition = it.getInt("select_position") } } - 如果是Navigation组件版本低于2.4.0,需要开启多回退栈支持才能在底部导航切换时保存状态:给底部导航菜单的每个item添加
android:menuCategory="secondary"属性,或者在导航跳转配置中添加popUpToSaveState="true"和restoreState="true"属性。2.4.0及以上版本默认开启多回退栈支持,无需额外配置。
3. 本地持久化存储(适配进程销毁场景)
如果需要在App退后台被杀死、重启后依然保留数据,可以选择SharedPreferences、Room数据库等本地存储方案:
- 每次用户修改数据时同步写入本地存储
- Fragment初始化时从本地读取数据回填到组件中
内容的提问来源于stack exchange,提问作者G.C
相关产品推荐
相关产品推荐

