Paging 3库中点击项加载更多并向RecyclerView追加数据如何实现
问题核心原因
你当前的实现存在两个核心问题导致数据被替换:
- 每次点击
Load more按钮都重新创建了PagingData流并调用submitData,Adapter会将新的PagingData识别为全新数据集,直接覆盖旧数据 PagingSource中硬编码返回nextKey = null,Paging3无法识别还有下一页数据,内部分页状态管理失效
具体修改步骤
1. 调整Paging配置,禁用自动预加载(适配点击才加载的需求)
你需要在构造Pager时指定PagingConfig,关闭滚动自动预加载的逻辑:
val pagingConfig = PagingConfig( pageSize = 50, // 你设置的单页数据量 prefetchDistance = 0, // 禁用预加载,滚动到底部不会自动触发下页请求 enablePlaceholders = false, initialLoadSize = 50 )
2. 修正PagingSource逻辑,正确返回分页key
不要硬写nextKey = null,也不要用外部的pagingTasksInput.pageNumber覆盖Paging内部维护的页码,让Paging3自行管理分页状态:
override suspend fun load(params: LoadParams<Int>): LoadResult<Int, TaskDto> { val pageNumber = params.key ?: DEFAULT_PAGE_INDEX return try { val response = tasksApi.getTasks( token = "Bearer " + NicoPrefs.getSSOAccessToken(), status = pagingTasksInput.status, type = pagingTasksInput.type, activity = pagingTasksInput.activity, sort = pagingTasksInput.sort, sortBy = pagingTasksInput.sortBy, pageNumber = pageNumber, // 直接用Paging内部维护的页码 pageLimit = pagingTasksInput.pageLimit, assignee = pagingTasksInput.assignee ) val data = response.result.orEmpty() // 根据返回数据量判断是否还有下一页,也可以用接口返回的总页数/是否为最后一页字段判断 val nextKey = if (data.size == pagingTasksInput.pageLimit) pageNumber + 1 else null LoadResult.Page( data = data, prevKey = if (pageNumber == DEFAULT_PAGE_INDEX) null else pageNumber - 1, nextKey = nextKey // 正确返回下一页页码 ) } catch (exception: IOException) { LoadResult.Error(exception) } catch (exception: HttpException) { LoadResult.Error(exception) } }
3. ViewModel中只初始化一次Paging流
不要每次点击都重新生成Paging流,将流缓存到ViewModel中复用:
class TestViewModel : ViewModel() { // 只在ViewModel初始化时创建一次Paging流,全局复用 val pagingTasksFlow = Pager( config = pagingConfig, pagingSourceFactory = { TasksPagingSource(pagingTasksInput) } ).flow .map { it.insertFooterItem(TaskDto(footer = "FOOTER", description = "Load more")) } .cachedIn(viewModelScope) // 缓存流,避免页面重建重新加载 }
4. 页面端只收集一次Paging流
将流收集逻辑移到onViewCreated中,只执行一次,不要放到点击事件中:
override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) // 只初始化一次流收集 viewLifecycleOwner.lifecycleScope.launch { viewLifecycleOwner.repeatOnLifecycle(Lifecycle.State.STARTED) { testViewModel.pagingTasksFlow.collectLatest { pagingData -> assignedTasksPagingAdapter?.submitData(pagingData) } } } }
5. 点击LoadMore按钮触发下页加载
在你的页脚按钮点击事件中加入触发加载的逻辑即可,Paging3会自动将新请求到的数据追加到原有列表后:
// 页脚Load more按钮点击回调 fun onLoadMoreClick() { assignedTasksPagingAdapter?.let { adapter -> val appendState = adapter.loadState.append // 仅当还有下页且没有在加载中时触发请求 if (appendState is LoadState.NotLoading && !appendState.endOfPaginationReached) { adapter.retry() } } }
补充说明
只要你正确复用同一个Paging流,Paging3内部会自动维护所有已加载的分页数据,新加载的页会自动追加到列表尾部,submitData方法只会做增量更新,不会全量替换原有数据。同时需要确保你的PagingDataAdapter的DiffUtil.ItemCallback正确实现了新旧项的对比逻辑。
内容的提问来源于stack exchange,提问作者Venkatesh Kashyap
相关产品推荐
相关产品推荐

