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

RecyclerView滚动时显示错误电影图片,多次加载后才显示正确求助

解决RecyclerView Adapter图片加载时显示旧图片的问题

哥们,你遇到的这个问题是RecyclerView开发里超常见的「ViewHolder复用导致图片加载混乱」的坑,核心原因很简单:RecyclerView会复用滚动出屏幕的ViewHolder来显示新条目,但如果之前ViewHolder绑定的图片加载任务还没完成,新条目绑定后,旧任务完成时会把旧图片设置到ImageView上,直到新的加载任务完成才会替换成正确的图片,就出现了你说的多次切换的情况。

下面给你几个靠谱的解决思路,按推荐程度排序:

1. 直接用成熟的图片加载库(最省心、最推荐)

自己手动写图片下载逻辑很容易踩复用的坑,Glide、Picasso、Coil这类主流图片加载库都已经内置处理了ViewHolder复用的问题——它们会自动取消当前ViewHolder上未完成的旧加载任务,同时支持内存/磁盘缓存、占位图、错误图等功能,代码还特别简洁。

比如用Glide的示例代码:

@Override
public void onBindViewHolder(MovieViewHolder holder, int position) {
    Movie currentMovie = movieList.get(position);
    
    Glide.with(holder.itemView.getContext())
         .load(currentMovie.getImageUrl())
         .placeholder(R.drawable.default_movie_placeholder) // 加载过程中显示的占位图
         .error(R.drawable.movie_load_error) // 加载失败时显示的图
         .into(holder.movieImageView);
}

用这类库基本能一键解决你的问题,还能省掉很多自己处理缓存、线程的麻烦。

2. 手动处理:重置ImageView+取消旧加载任务

如果必须自己实现图片下载逻辑,那要做两件事:

第一步:绑定新数据前重置ImageView

在onBindViewHolder的最开始,先把ImageView的内容清空或者设置为占位图,避免旧图片先显示出来:

@Override
public void onBindViewHolder(MovieViewHolder holder, int position) {
    // 先重置ImageView,清除旧内容
    holder.movieImageView.setImageResource(R.drawable.default_movie_placeholder);
    
    // 再绑定新数据、启动新的图片加载
    Movie currentMovie = movieList.get(position);
    startImageDownload(currentMovie.getImageUrl(), holder.movieImageView);
}

第二步:取消ViewHolder上未完成的旧加载任务

你需要在ViewHolder中保存当前的加载任务引用,当重新绑定时,先取消之前的任务,避免它完成后设置旧图片。比如用AsyncTask的示例:

// 自定义ViewHolder,保存当前加载任务
class MovieViewHolder extends RecyclerView.ViewHolder {
    ImageView movieImageView;
    AsyncTask<?, ?, ?> currentDownloadTask;

    public MovieViewHolder(@NonNull View itemView) {
        super(itemView);
        movieImageView = itemView.findViewById(R.id.iv_movie);
    }
}

@Override
public void onBindViewHolder(MovieViewHolder holder, int position) {
    // 取消之前未完成的下载任务
    if (holder.currentDownloadTask != null) {
        holder.currentDownloadTask.cancel(true);
    }

    // 重置ImageView
    holder.movieImageView.setImageResource(R.drawable.default_movie_placeholder);

    Movie currentMovie = movieList.get(position);
    // 启动新的下载任务,并保存引用到ViewHolder
    holder.currentDownloadTask = new AsyncTask<String, Void, Bitmap>() {
        @Override
        protected Bitmap doInBackground(String... urls) {
            // 下载图片前先判断任务是否被取消
            if (isCancelled()) {
                return null;
            }
            return downloadBitmapFromUrl(urls[0]); // 你的图片下载逻辑
        }

        @Override
        protected void onPostExecute(Bitmap bitmap) {
            // 任务没被取消且图片不为空时,才设置图片
            if (!isCancelled() && bitmap != null) {
                holder.movieImageView.setImageBitmap(bitmap);
            }
        }
    }.execute(currentMovie.getImageUrl());
}

注意:在doInBackground和onPostExecute里都要判断任务是否被取消,避免无用操作。

总结

优先推荐用成熟的图片加载库,能帮你规避绝大多数图片加载相关的问题;如果必须自己实现,一定要记得重置ImageView和取消旧加载任务这两个关键点。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.19 10:00:19