You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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的复用逻辑,不会出现错位问题。

问题复现效果

异常效果截图1
异常效果截图2

对照代码运行效果

正常效果截图1
正常效果截图2

内容的提问来源于stack exchange,提问作者user10557996

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.28 11:36:16