如何避免PagingAdapter出现重复条目?DiffUtil.ItemCallback不生效怎么办
为什么你的DiffUtil配置没有生效
你对DiffUtil.ItemCallback的功能存在认知偏差,它的核心作用是对比适配器已加载的旧数据集和新提交的PagingData的差异,用于生成RecyclerView的局部更新指令(比如条目新增/删除/修改的动画、局部刷新),不会对单个PagingData内部的重复数据、或跨页加载的重复数据做自动过滤。
简单说:如果你的数据源本身返回的PagingData就包含多个相同ID的Person对象,DiffUtil不会主动删除这些重复条目,只会判断两个条目是否是同一个对象、是否需要刷新内容,完全没有去重的作用。
实现按ID去重的可行方案
推荐按优先级从高到低选择以下方案:
数据源层去重(最优方案)
从数据产生的源头处理重复问题,避免后续所有链路的冗余处理:- 如果是直接从网络加载分页的
PagingSource,在load方法拿到接口返回的列表后,先按ID去重再封装为LoadResult.Page返回,示例代码:
override suspend fun load(params: LoadParams<Int>): LoadResult<Int, Person> { return try { val page = params.key ?: 1 val response = apiService.getPersonList(page, params.loadSize) // 按ID去重 val uniqueList = response.data.distinctBy { it.id } LoadResult.Page( data = uniqueList, prevKey = if (page == 1) null else page - 1, nextKey = if (uniqueList.isEmpty()) null else page + 1 ) } catch (e: Exception) { LoadResult.Error(e) } }- 如果用了
RemoteMediator做本地+网络的分页架构,直接在Room数据库的Person表的id字段加@PrimaryKey唯一约束,重复ID的条目写入时会自动覆盖/跳过,从本地查询返回的列表自然不会有重复。
- 如果是直接从网络加载分页的
PagingData变换层去重
如果无法修改数据源,可在ViewModel层对PagingData流做变换去重,示例代码:fun getPeople(): Flow<PagingData<Person>> { val existedIds = mutableSetOf<Int>() return Pager( config = PagingConfig(pageSize = 20, enablePlaceholders = false) ) { PersonPagingSource() }.flow.map { pagingData -> pagingData.filter { person -> val notExisted = !existedIds.contains(person.id) if (notExisted) existedIds.add(person.id) notExisted } } }注意该方案需要处理刷新场景,下拉刷新时需要清空
existedIds集合避免新数据被误过滤。
内容的提问来源于stack exchange,提问作者Hakan Erbaş
相关产品推荐
相关产品推荐

