非Room数据源下Android Paging3 PagingSource失效列表跳转问题求解
问题根因
Paging 3 官方默认的getRefreshKey逻辑默认每页返回数据量等于配置的pageSize,但你的实现中存在单页返回多页合并的批量数据,页码跨度和实际承载的条目跨度不匹配,导致基于锚点页的prev/nextKey计算出的刷新页码完全错位。
正确解决方案
核心是利用PagingState.Page自带的itemsBefore属性统计锚点对应的真实全局条目位置,再计算正确刷新页码:
1. 重写getRefreshKey逻辑
override fun getRefreshKey(state: PagingState<Int, CustomData>): Int? { return state.anchorPosition?.let { anchorPosition -> val anchorPage = state.closestPageToPosition(anchorPosition) ?: return@let null // 计算锚点对应的真实全局条目位置:该页之前的前置条目数 + 锚点在当前页内的偏移量 val realGlobalPos = anchorPage.itemsBefore + (anchorPosition - anchorPage.anchorPositionInPage) // 按单页大小取整得到正确刷新页码 realGlobalPos / pageSize } }
2. 调整load方法优化点
你当前load方法强行修改loadSize的逻辑可以简化,直接使用params.loadSize即可,Paging 3会根据PagingConfig中的initialLoadSize、pageSize自动传递正确的加载数量:
override suspend fun load(params: LoadParams<Int>): LoadResult<Int, CustomData> { val pagePosition = params.key ?: STARTING_PAGE_INDEX val loadSize = params.loadSize return try { val dataResult = dataRepository.getPagedData( pagePosition = pagePosition, loadSize = loadSize, pageSize = pageSize ) val nextKey = if (dataResult.isEmpty() || dataResult.size < pageSize) { null } else { pagePosition + (loadSize / pageSize) } LoadResult.Page( data = dataResult, prevKey = if (pagePosition == STARTING_PAGE_INDEX) null else pagePosition - 1, nextKey = nextKey ) } catch (exception: Exception) { LoadResult.Error(exception) } }
3. 额外优化建议
如果仍偶现刷新后闪烁,可以调整PagingConfig配置:
- 保持
initialLoadSize = pageSize * 3的默认配置,保证首次加载数据足够填充视口 - 把
jumpThreshold设置为pageSize,降低意外跳转概率
效果验证
以你提到的两个场景:
- 未滚动时锚点在第7条,计算得全局位置7,除以单页10得页码0,刷新页正确
- 滚动到第140条时,即使
anchorPosition显示为5,anchorPage.itemsBefore为135,加上页内偏移5得全局位置140,除以10得页码14,刷新页正确
内容的提问来源于stack exchange,提问作者MEX
相关产品推荐
相关产品推荐

