Jetpack Compose导航时如何保存LazyColumn的分页状态?
解决方案
最优实现方案(官方推荐,改造成本最低)
Pager、PagingSource都属于非Parcelable/序列化的复杂对象,无法通过rememberSaveable存入Bundle;同时放在Composable中用remember存储的状态会在导航跳转时随Composable移出Composition而销毁,返回后就会重新初始化拉取数据。
最简单的实现方案是将分页逻辑迁移到ViewModel中,利用ViewModel与导航目的地绑定的生命周期保留状态:
- 在对应页面的ViewModel中初始化Pager,并通过
cachedIn绑定ViewModel作用域缓存分页数据
class SampleViewModel : ViewModel() { // 在此处初始化你的自定义PagingSource private val myPagingSource = MyCustomPagingSource() val pagingFlow = Pager( config = PagingConfig(pageSize = 25), initialKey = 0, pagingSourceFactory = { myPagingSource } ).flow // 核心:将分页数据缓存到ViewModel作用域,ViewModel不销毁则缓存不丢失 .cachedIn(viewModelScope) }
- 改造Composable代码,直接从ViewModel取分页流,不需要在Composable中创建Pager
@Composable fun SampleScreen( composeNavController: NavHostController? = null, // 导航库会自动保留当前目的地对应的ViewModel实例,跳转不会销毁 viewModel: SampleViewModel = viewModel() ) { val lazyPagingItems = viewModel.pagingFlow.collectAsLazyPagingItems() // rememberLazyListState内部默认实现了状态保存,数据存在时滚动位置自动恢复 val listState = rememberLazyListState() LazyColumn(state = listState) { itemsIndexed(items = lazyPagingItems) { index, item -> MyRowItem(item) { composeNavController?.navigate(...) } } } }
方案说明
- 导航跳转时只要当前页面没有被从导航栈中pop移除,对应的ViewModel就不会被销毁,已经拉取的分页缓存、加载状态都会完整保留,返回页面时不需要重新请求后端接口
rememberLazyListState本身已支持状态持久化,只要分页数据存在,返回页面会自动恢复到之前的滚动位置,不需要额外处理
备选方案(不使用ViewModel的场景)
如果确实需要在Composable内部维护分页状态,可以自定义Saver分别保存分页的当前加载key、滚动位置的索引与偏移,返回页面时用保存的key作为Pager的initialKey初始化,再手动恢复滚动位置,该方案实现成本更高,非必要不推荐。
内容的提问来源于stack exchange,提问作者Damiancioo
相关产品推荐
相关产品推荐

