RecyclerView分页加载含Null数据时显示异常问题求助
问题解决方案
核心问题分析
你的问题根源有三点:
- API返回的最后一页包含Null数据,直接传入Paging库导致Adapter拿到无效条目
- Adapter使用类级别共用Binding实例,导致ViewHolder复用时视图内容混乱
- 未正确处理Null数据+禁用ViewHolder复用,最终引发重复显示/异常视图问题
分步修复
1. 过滤PagingSource中的Null数据
在DocPagingSource的load方法中,直接过滤掉返回数据里的Null条目,从源头阻止无效数据进入分页流程:
修改后的load方法:
override suspend fun load(params: LoadParams<Int>): LoadResult<Int, Data> { return try { val currentPage = params.key ?: 1 val city: String = "" val response = docRepository.getDoctors(city, currentPage) val body = response.body() ?: throw Exception("Empty response body") val totalPages = Math.ceil(body.total.toDouble() / 5).toInt() // 过滤所有Null的医生数据 val validData = body.data.filterNotNull() LoadResult.Page( data = validData, prevKey = if (currentPage == 1) null else currentPage - 1, // 修正之前错误的prevKey值 nextKey = if (currentPage == totalPages) null else currentPage + 1 ) } catch (e: HttpException) { LoadResult.Error(e) } catch (e: Exception) { LoadResult.Error(e) } }
2. 修复Adapter的ViewHolder与Bind逻辑
当前Adapter的Binding是类级别变量,会导致所有ViewHolder共用同一个Binding实例,这是视图混乱的核心原因。需要将Binding移到ViewHolder内部,同时完善Null数据的处理逻辑:
修改后的DocAdapter代码:
class DocAdapter(val context: Context) : PagingDataAdapter<Data, DocAdapter.DocViewHolder>(DiffUtil()) { inner class DocViewHolder(private val binding: ItemDoctorsBinding) : RecyclerView.ViewHolder(binding.root) { fun bind(item: Data?) { binding.apply { // 为所有控件设置默认值,避免复用旧数据 txtDocCity.text = item?.city ?: "" txtDocName.text = item?.docName ?: "" txtDocFees.text = item?.docConsultationFee ?: "" txtDocYOE.text = item?.docYoE ?: "" txtDocSpecialisation.text = item?.docSpecialisation ?: "" // 处理图片加载的Null情况,设置默认占位图 if (item?.docProfileImgUrl != null) { Glide.with(context) .load(item.docProfileImgUrl) .fitCenter() .diskCacheStrategy(DiskCacheStrategy.ALL) .into(docPhoto) } else { Glide.with(context) .load(R.drawable.default_doctor_avatar) // 替换为你的默认占位图资源 .fitCenter() .into(docPhoto) } } } } override fun onBindViewHolder(holder: DocViewHolder, position: Int) { val item = getItem(position) holder.bind(item) // 移除setIsRecyclable(false),恢复ViewHolder复用,提升性能 } override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): DocViewHolder { val inflater = LayoutInflater.from(context) val binding = ItemDoctorsBinding.inflate(inflater, parent, false) return DocViewHolder(binding) } class DiffUtil : androidx.recyclerview.widget.DiffUtil.ItemCallback<Data>() { override fun areItemsTheSame(oldItem: Data, newItem: Data): Boolean { return oldItem.docId == newItem.docId } override fun areContentsTheSame(oldItem: Data, newItem: Data): Boolean { // 若Data不是data class,建议逐个字段比较,避免引用比较出错 return oldItem == newItem } } }
3. 验证ViewModel与Activity代码
你的ViewModel和Activity代码逻辑正常,PagingConfig的pageSize与API每页返回条目数(5)匹配,无需修改。
问题原因复盘
- 禁用
setIsRecyclable(false):会导致RecyclerView无法复用ViewHolder,不仅性能暴跌,还会因视图回收逻辑异常出现奇怪的默认视图 - 未过滤Null数据:Paging库将Null数据传入Adapter,而Adapter未做防御处理,复用ViewHolder时会显示旧数据
- 共用Binding实例:所有ViewHolder共享同一个Binding,滚动时视图内容被覆盖,引发显示混乱
内容的提问来源于stack exchange,提问作者Amit Kumar
相关产品推荐
相关产品推荐

