Android RecyclerView条件加载图片错位重复显示问题
问题根因
这是RecyclerView ViewHolder复用机制导致的经典图片错位问题。
RecyclerView滚动时不会为每个列表项新建View实例,滑出屏幕的ViewHolder会被直接回收,复用到刚滑入可视区域的列表项上。你出问题的代码只写了imageName非空时加载图片的逻辑:如果某个ViewHolder之前加载过真实图片,被回收后绑定到没有配图的新列表项时,你没有重置对应ImageView的内容,之前加载的旧图片就会残留在控件上,滚动次数越多,错位残留的图片就越多。
你写的对照代码之所以不出现错位,是因为不管imageName是不是空,都会执行Glide加载流程——哪怕加载的是不存在的文件路径,Glide也会把ImageView上之前残留的内容覆盖掉,自然不会留下旧图。
修复方法
给onBindViewHolder补全空值分支的处理逻辑即可,两种写法都能正常运行:
- 写法1:全分支交给Glide处理,空值时直接加载默认加号图标
override fun onBindViewHolder(holder: ViewHolder, position: Int) { val record = records[position] if (!record.imageName.isNullOrEmpty()){ Glide.with(recordInfoTitle.context) .load("$imagesPath$FORWARD_SLASH${record.imageName}") .into(holder.recordCover) } else { Glide.with(recordInfoTitle.context) .load(R.drawable.ic_add_plus) // 替换成你项目里的加号图标资源ID .into(holder.recordCover) } }
- 写法2:空值时手动清空加载任务、设置默认图
override fun onBindViewHolder(holder: ViewHolder, position: Int) { val record = records[position] if (!record.imageName.isNullOrEmpty()){ Glide.with(recordInfoTitle.context) .load("$imagesPath$FORWARD_SLASH${record.imageName}") .into(holder.recordCover) } else { // 先清空ImageView上挂着的旧加载任务,防止异步返回的旧图覆盖当前内容 Glide.with(recordInfoTitle.context).clear(holder.recordCover) holder.recordCover.setImageResource(R.drawable.ic_add_plus) // 替换成你项目里的加号图标资源ID } }
避坑提醒
- 编写
onBindViewHolder逻辑时,只要是给列表项控件设置内容、状态,必须覆盖所有逻辑分支,绝对不能出现「满足条件才设置属性,不满足就什么都不做」的写法,否则复用的时候必然会出现内容残留错位。 - 列表中用Glide加载图片时,不要手动给ImageView设置tag拦截加载流程,只要每次绑定都走Glide的加载/clear流程,Glide本身已经适配了RecyclerView的复用逻辑,不会出现错位问题。
问题复现效果


对照代码运行效果


内容的提问来源于stack exchange,提问作者user10557996
相关产品推荐
相关产品推荐

