如何从Glide加载的RecyclerView中移除点击的图片
解决RecyclerView移除Glide加载图片后出现重复项的问题
问题描述
我查了大量资料,想找到从Glide加载图片的RecyclerView里移除点击图片的方法,但没找到相关内容。能看到的示例基本都围绕Glide的diskCacheStrategy这类缓存策略展开,没人讲怎么从RecyclerView中移除图片。
我的需求是移除列表中被点击的图片,当前填充RecyclerView的代码:
@Override public void onBindViewHolder(@NonNull ImageGalleryAdapter.MyViewHolder holder, int position) { fbPhotos fbPhotos = mFbPhotos[position]; ImageView imageView = holder.mPhotoImageView; Glide.with(mContext) .load(fbPhotos.getUrl()) .placeholder(R.drawable.ic_cloud_off_red) .into(imageView); }
检测图片点击的代码:
public class MyViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener { public ImageView mPhotoImageView; public MyViewHolder(View itemView) { super(itemView); mPhotoImageView = itemView.findViewById(R.id.iv_photo); itemView.setOnClickListener(this); } @Override public void onClick(View view) { int position = getAdapterPosition(); if(position != RecyclerView.NO_POSITION) { fbPhotos fbPhotos = mFbPhotos[position]; } } }
完整代码:
public class frag_photos extends Fragment { public frag_photos() { // Required empty public constructor } private fbPhotos[] mFbPhotos; private Context mContext; SwipeRefreshLayout swipeLayout; RecyclerView recyclerView; @Override public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { View view = inflater.inflate(R.layout.frag_photos, container, false); RecyclerView.LayoutManager layoutManager = new GridLayoutManager(getContext(), 2); recyclerView = view.findViewById(R.id.rv_images); recyclerView.setHasFixedSize(true); recyclerView.setLayoutManager(layoutManager); ImageGalleryAdapter adapter = new ImageGalleryAdapter(getContext(), fbPhotos.getFBPhotos()); recyclerView.setAdapter(adapter); //Getting SwipeContainerLayout swipeLayout = view.findViewById(R.id.swipe_container); //swip listener swipeLayout.setOnRefreshListener(() -> { Log.d("test", "regresh"); swipeLayout.setRefreshing(false); }); return view; } @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); } private class ImageGalleryAdapter extends RecyclerView.Adapter<ImageGalleryAdapter.MyViewHolder> { @NonNull @Override public ImageGalleryAdapter.MyViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { Context context = parent.getContext(); LayoutInflater inflater = LayoutInflater.from(context); View photoView = inflater.inflate(R.layout.item_photo, parent, false); ImageGalleryAdapter.MyViewHolder viewHolder = new ImageGalleryAdapter.MyViewHolder(photoView); return viewHolder; } @Override public void onBindViewHolder(@NonNull ImageGalleryAdapter.MyViewHolder holder, int position) { fbPhotos fbPhotos = mFbPhotos[position]; ImageView imageView = holder.mPhotoImageView; Glide.with(mContext) .load(fbPhotos.getUrl()) .placeholder(R.drawable.ic_cloud_off_red) .into(imageView); } @Override public int getItemCount() { return (mFbPhotos.length); } public class MyViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener { public ImageView mPhotoImageView; public MyViewHolder(View itemView) { super(itemView); mPhotoImageView = itemView.findViewById(R.id.iv_photo); itemView.setOnClickListener(this); } @Override public void onClick(View view) { int position = getAdapterPosition(); if(position != RecyclerView.NO_POSITION) { fbPhotos fbPhotos = mFbPhotos[position]; } } } public ImageGalleryAdapter(Context context, List<fbPhotos> fbPhotos) { mContext = context; mFbPhotos = fbPhotos.toArray(new fbPhotos[0]); } } }
我尝试用notifyItemRemoved(position)方法移除图片,虽然能删掉点击的项,但每次点击都会在列表里添加最后一张图片的副本(表现为删除一项后,最后一项重复出现)。
问题根源
你当前用固定长度的数组存储数据,调用notifyItemRemoved(position)时,RecyclerView的视图会更新,但数组里的数据并没有真正删除对应元素,再加上RecyclerView的视图复用机制,就会导致最后一项被重复绑定显示。
解决步骤
1. 替换数据存储类型
把原来的fbPhotos[]数组换成List<fbPhotos>,List支持动态添加/删除元素,能保证数据和视图同步。
2. 修改适配器代码
- 让适配器直接持有List引用,不用转成数组
- 在点击事件中先删除List中的对应元素,再通知适配器更新
- 绑定视图前清空ImageView,避免复用显示旧图片
修改后的完整代码示例
Fragment部分修改
public class frag_photos extends Fragment { public frag_photos() { // Required empty public constructor } // 把数组换成List private List<fbPhotos> mFbPhotos; private Context mContext; SwipeRefreshLayout swipeLayout; RecyclerView recyclerView; @Override public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { View view = inflater.inflate(R.layout.frag_photos, container, false); RecyclerView.LayoutManager layoutManager = new GridLayoutManager(getContext(), 2); recyclerView = view.findViewById(R.id.rv_images); recyclerView.setHasFixedSize(true); recyclerView.setLayoutManager(layoutManager); ImageGalleryAdapter adapter = new ImageGalleryAdapter(getContext(), fbPhotos.getFBPhotos()); recyclerView.setAdapter(adapter); swipeLayout = view.findViewById(R.id.swipe_container); swipeLayout.setOnRefreshListener(() -> { Log.d("test", "regresh"); swipeLayout.setRefreshing(false); }); return view; } @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); } // 修改后的适配器 private class ImageGalleryAdapter extends RecyclerView.Adapter<ImageGalleryAdapter.MyViewHolder> { private List<fbPhotos> mFbPhotos; private Context mContext; @NonNull @Override public ImageGalleryAdapter.MyViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { Context context = parent.getContext(); LayoutInflater inflater = LayoutInflater.from(context); View photoView = inflater.inflate(R.layout.item_photo, parent, false); return new MyViewHolder(photoView); } @Override public void onBindViewHolder(@NonNull ImageGalleryAdapter.MyViewHolder holder, int position) { fbPhotos photo = mFbPhotos.get(position); ImageView imageView = holder.mPhotoImageView; // 绑定新数据前清空旧图片,避免复用错误 Glide.with(mContext).clear(imageView); Glide.with(mContext) .load(photo.getUrl()) .placeholder(R.drawable.ic_cloud_off_red) .into(imageView); } @Override public int getItemCount() { return mFbPhotos.size(); } public class MyViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener { public ImageView mPhotoImageView; public MyViewHolder(View itemView) { super(itemView); mPhotoImageView = itemView.findViewById(R.id.iv_photo); itemView.setOnClickListener(this); } @Override public void onClick(View view) { int position = getAdapterPosition(); if(position != RecyclerView.NO_POSITION) { // 1. 真正删除数据集合中的元素 mFbPhotos.remove(position); // 2. 通知适配器移除对应位置的视图 notifyItemRemoved(position); // 可选:通知后续项索引变化,防止绑定错误 notifyItemRangeChanged(position, mFbPhotos.size()); } } } // 构造方法直接接收List public ImageGalleryAdapter(Context context, List<fbPhotos> fbPhotos) { mContext = context; mFbPhotos = fbPhotos; } } }
关键说明
- 必须先修改数据集合,再调用
notifyItemRemoved,否则视图和数据不同步会导致复用错误 - 用
Glide.with(mContext).clear(imageView)可以避免复用的ViewHolder显示之前加载的图片,这在列表项删除、排序场景中很重要
内容的提问来源于stack exchange,提问作者StealthRT
相关产品推荐
相关产品推荐

