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

RecyclerView:调用notifyItemChanged时排除YouTube缩略图刷新

解决RecyclerView调用notifyItemChanged()时不刷新YouTube缩略图的问题

嘿,我完全懂你的需求——每次调用notifyItemChanged()更新列表项时,不想让已经加载好的YouTube缩略图重新刷新,避免多余的网络请求或者重复播放加载动画对吧?下面给你两种实用的解决方案,按需选择就行:

方法一:用DiffUtil实现精准局部更新

默认的notifyItemChanged()会重新绑定整个ViewHolder,包括缩略图。DiffUtil可以帮我们对比新旧数据的差异,只更新真正发生变化的UI部分,从根源上避免缩略图重复加载。

步骤1:创建DiffUtil对比回调类

public class VideoDiffCallback extends DiffUtil.Callback {
    private List<Video> oldVideos;
    private List<Video> newVideos;

    public VideoDiffCallback(List<Video> oldVideos, List<Video> newVideos) {
        this.oldVideos = oldVideos;
        this.newVideos = newVideos;
    }

    @Override
    public int getOldListSize() {
        return oldVideos.size();
    }

    @Override
    public int getNewListSize() {
        return newVideos.size();
    }

    @Override
    public boolean areItemsTheSame(int oldItemPosition, int newItemPosition) {
        // 用视频的唯一标识判断是不是同一个列表项,比如视频ID
        return oldVideos.get(oldItemPosition).getId().equals(newVideos.get(newItemPosition).getId());
    }

    @Override
    public boolean areContentsTheSame(int oldItemPosition, int newItemPosition) {
        Video oldVideo = oldVideos.get(oldItemPosition);
        Video newVideo = newVideos.get(newItemPosition);
        // 只对比需要更新的字段(比如标题、播放量),缩略图URL不在对比范围内
        return oldVideo.getTitle().equals(newVideo.getTitle())
                && oldVideo.getViewCount().equals(newVideo.getViewCount());
        // 如果缩略图URL有可能变化,这里再加上:&& oldVideo.getThumbnailUrl().equals(newVideo.getThumbnailUrl())
    }

    @Nullable
    @Override
    public Object getChangePayload(int oldItemPosition, int newItemPosition) {
        // 当内容不一致时,返回需要更新的字段集合
        Video oldVideo = oldVideos.get(oldItemPosition);
        Video newVideo = newVideos.get(newItemPosition);
        Bundle payload = new Bundle();
        if (!oldVideo.getTitle().equals(newVideo.getTitle())) {
            payload.putString("title", newVideo.getTitle());
        }
        if (!oldVideo.getViewCount().equals(newVideo.getViewCount())) {
            payload.putString("viewCount", newVideo.getViewCount());
        }
        // 故意不加入缩略图相关字段,这样就不会触发缩略图刷新
        return payload.size() == 0 ? null : payload;
    }
}

步骤2:在适配器中替换更新逻辑

把原来直接更新列表+调用notify的方式,改成用DiffUtil计算差异后更新:

public void updateVideos(List<Video> newVideos) {
    VideoDiffCallback diffCallback = new VideoDiffCallback(this.videos, newVideos);
    DiffUtil.DiffResult diffResult = DiffUtil.calculateDiff(diffCallback);
    this.videos.clear();
    this.videos.addAll(newVideos);
    diffResult.dispatchUpdatesTo(this);
}

步骤3:修改onBindViewHolder处理局部更新

在适配器的onBindViewHolder中加入payload判断,只更新指定字段:

@Override
public void onBindViewHolder(@NonNull ViewHolder holder, int position, @NonNull List<Object> payloads) {
    if (payloads.isEmpty()) {
        // payload为空时,正常绑定所有UI(包括首次加载缩略图)
        onBindViewHolder(holder, position);
    } else {
        // 只更新payload里指定的内容,完全跳过缩略图逻辑
        Bundle bundle = (Bundle) payloads.get(0);
        Video video = videos.get(position);
        if (bundle.containsKey("title")) {
            holder.titleTextView.setText(video.getTitle());
        }
        if (bundle.containsKey("viewCount")) {
            holder.viewCountTextView.setText(video.getViewCount());
        }
    }
}

@Override
public void onBindViewHolder(@NonNull ViewHolder holder, int position) {
    Video video = videos.get(position);
    // 正常加载缩略图的逻辑(比如用Glide/Picasso)
    Glide.with(holder.itemView.getContext())
            .load(video.getThumbnailUrl())
            .placeholder(R.drawable.loading_placeholder)
            .into(holder.thumbnailImageView);
    // 其他UI绑定
    holder.titleTextView.setText(video.getTitle());
    holder.viewCountTextView.setText(video.getViewCount());
}

方法二:手动判断跳过缩略图刷新

如果不想引入DiffUtil,也可以在每次绑定时,判断当前缩略图是否已经加载过对应URL,跳过重复加载:

@Override
public void onBindViewHolder(@NonNull ViewHolder holder, int position) {
    Video video = videos.get(position);
    // 把当前ImageView已加载的URL存在tag里,用来做对比
    String currentLoadedUrl = (String) holder.thumbnailImageView.getTag();
    if (currentLoadedUrl == null || !currentLoadedUrl.equals(video.getThumbnailUrl())) {
        // 只有URL变化时才重新加载缩略图
        Glide.with(holder.itemView.getContext())
                .load(video.getThumbnailUrl())
                .placeholder(R.drawable.loading_placeholder)
                .into(holder.thumbnailImageView);
        // 更新tag为当前URL
        holder.thumbnailImageView.setTag(video.getThumbnailUrl());
    }
    // 正常更新其他UI元素
    holder.titleTextView.setText(video.getTitle());
    holder.viewCountTextView.setText(video.getViewCount());
}

这种方法更简单直接,适合逻辑不复杂的场景;DiffUtil则更适合数据频繁变化、需要精准控制更新的场景,你可以根据项目情况选~

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.22 09:06:23