使用Bottom Navigation View切换标签页时如何保存RecyclerView状态
解决方案
问题根因
该状态丢失问题是Navigation Component默认切换标签页时会销毁旧Fragment实例、重建新实例导致的,进入详情页返回时没有销毁Fragment实例,所以滚动状态可以正常保留。
修复步骤
1. 升级Navigation依赖到2.4.0及以上版本
该版本开始原生支持Bottom Navigation多返回栈特性,每个标签页的Fragment状态会独立保存,无需自行实现Fragment复用逻辑。
修改模块级build.gradle依赖:
implementation "androidx.navigation:navigation-fragment-ktx:2.7.5" implementation "androidx.navigation:navigation-ui-ktx:2.7.5"
2. 正确绑定BottomNavigationView和NavController
不要自定义OnItemSelectedListener处理页面跳转,直接使用官方扩展方法绑定,会自动开启多返回栈能力:
val navHostFragment = supportFragmentManager.findFragmentById(R.id.nav_host_fragment) as NavHostFragment val navController = navHostFragment.navController binding.bottomNav.setupWithNavController(navController)
注意需保证bottom_nav_menu.xml中每个item的id,和nav_graph.xml中对应标签页Fragment的id完全一致。
3. 规范数据和状态存储逻辑
- 所有电影列表数据存储在对应标签页Fragment的独立ViewModel中,不要在
onViewCreated生命周期中每次切回页面都重新发起列表请求,避免列表重新渲染导致滚动位置重置。 - 如确实需要切回页面刷新数据,提前保存滚动状态,待数据更新完成后再恢复:
// 页面切走时保存滚动状态 private var listScrollState: Parcelable? = null override fun onPause() { super.onPause() listScrollState = binding.movieRv.layoutManager?.onSaveInstanceState() } // 列表数据更新完成后恢复滚动状态 movieAdapter.submitList(fetchedMovieList) { listScrollState?.let { state -> binding.movieRv.layoutManager?.onRestoreInstanceState(state) } }
4. 避免主动清空状态的操作
不要在onDestroyView生命周期中执行RecyclerView的adapter置空、LayoutManager重置等操作,这类操作会主动清除已保存的滚动状态。
内容的提问来源于stack exchange,提问作者Ahmadddd4
相关产品推荐
相关产品推荐

