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
相关产品推荐
相关产品推荐

