Activity/Fragment重建(屏幕旋转)Paging3列表重复加载问题排查
问题根因
你代码的核心问题出在ViewModel中cachedIn方法的调用逻辑错误:PagingRx.cachedIn() 是返回新的带缓存能力的Flowable实例,你当前代码没有将返回值赋值给类成员flowable,等于缓存配置完全没有生效。每次Fragment因为旋转重建重新订阅flowable时,都会触发Pager重新创建PagingSource、从头加载数据。
修复方案
修改ViewModel的init()方法,将cachedIn的返回值赋值给flowable:
private void init() { CoroutineScope viewModelScope = ViewModelKt.getViewModelScope(this); Pager<Integer, Book> pager = new Pager<>( pagingConfig, () -> new BooksPagingSource(dataApi, preferencesHelper) ); flowable = PagingRx.getFlowable(pager); // 注意这里要把cachedIn的返回值赋值给flowable flowable = PagingRx.cachedIn(flowable, viewModelScope); }
修改后,PagingData会被缓存在ViewModel的生命周期内,旋转屏幕时ViewModel不会销毁,Fragment重建后重新订阅flowable会直接拿到已缓存的分页数据,不会触发重新加载,列表滚动位置也会自动保留。
getRefreshKey()调用场景说明
这个方法仅在PagingSource需要失效重建、整体刷新数据时才会被调用,常见触发场景包括:
- 手动调用
PagingDataAdapter.refresh()触发下拉刷新 - 调用
PagingSource.invalidate()主动让当前数据源失效 - 分页配置变更需要重新加载数据
它的作用是根据当前列表的浏览位置计算刷新的起始页码,保证刷新后列表不会跳回第一页,而是停在用户之前浏览的位置附近。你当前的getRefreshKey实现是符合要求的,不需要修改。
可选优化
你当前在Fragment中用requireActivity()获取ViewModel,意味着这个ViewModel的生命周期和Activity绑定,如果这个列表只在当前Fragment使用,建议改为Fragment级别的ViewModel,避免内存浪费:
// 把requireActivity()换成this,也就是Fragment自身 BooksViewModel viewModel = new ViewModelProvider(this).get(BooksViewModel.class);
内容的提问来源于stack exchange,提问作者Andrey Cherkasov
相关产品推荐
相关产品推荐

