RecyclerView适配器显示错误的图像

我有一个RecyclerView适配器,如下所示:

public class RecyclerAdapter extends RecyclerView.Adapter { private static Context context; private List mDataset; public RecyclerAdapter(Context context, List myDataset) { this.context = context; this.mDataset = myDataset; } public static class ViewHolder extends RecyclerView.ViewHolder implements View.OnCreateContextMenuListener, View.OnClickListener { public TextView title; public LinearLayout placeholder; public ViewHolder(View view) { super(view); view.setOnCreateContextMenuListener(this); title = (TextView) view.findViewById(R.id.title); placeholder = (LinearLayout) view.findViewById(R.id.placeholder); } } @Override public RecyclerAdapter.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.message_layout, parent, false); ViewHolder vh = new ViewHolder((LinearLayout) view); return vh; } @Override public void onBindViewHolder(ViewHolder holder, int position) { Message item = mDataset.get(position); holder.title.setText(item.getTitle()); int numImages = item.getImages().size(); if (numImages > 0) { View test = LayoutInflater.from(holder.placeholder.getContext()).inflate(R.layout.images, holder.placeholder, false); ImageView image = (ImageView) test.findViewById(R.id.image); Glide.with(context) .load("http://img.androidcookie.com/android/test.png") .fitCenter() .into(image); holder.placeholder.addView(test); } } @Override public int getItemCount() { return mDataset.size(); } } 

但是,RecyclerView中的某些项目不应显示图像。 我怎么能阻止这种情况发生?

我在onBindViewHolder()检查if (numImages > 0) {但是仍然没有阻止它显示不应该有图像的项目的图像。

问题出在onBindViewHolder上,这里:

  if (numImages > 0) { View test = LayoutInflater.from(holder.placeholder.getContext()).inflate(R.layout.images, holder.placeholder, false); ImageView image = (ImageView) test.findViewById(R.id.image); Glide.with(context) .load("http://img.androidcookie.com/android/test.png") .fitCenter() .into(image); holder.placeholder.addView(test); } 

如果numImages等于0,则只需允许先前启动的加载进入您重复使用的视图中。 完成后,它仍会将旧图像加载到视图中。 为了防止这种情况,请通过调用clear告诉Glide取消之前的加载:

  if (numImages > 0) { View test = LayoutInflater.from(holder.placeholder.getContext()).inflate(R.layout.images, holder.placeholder, false); ImageView image = (ImageView) test.findViewById(R.id.image); Glide.with(context) .load("http://img.androidcookie.com/android/test.png") .fitCenter() .into(image); holder.placeholder.addView(test); } else { Glide.clear(image); } 

当您调用into() ,Glide会为您处理取消旧负载的问题。 如果你不打算打电话into() ,你必须自己打电话给clear()

每次对onBindViewHolder的调用都必须包含load()调用或clear()调用。

我也遇到了RecyclerView显示错误图像的问题。 这是因为RecyclerView没有为每个新列表项膨胀视图:而是列表项正在被回收。

通过回收视图,我们可以粗略地理解克隆视图。 克隆的视图可能具有先前交互的图像集。

如果您使用Picasso,Glide或其他lib进行异步加载,这尤其公平。 这些库包含对ImageView的引用,并在加载图像时在该引用上设置图像。

到图像加载时,项目视图可能已克隆,图像将被设置为错误的克隆

总而言之,我通过限制RecyclerView克隆我的项目视图来解决这个问题:

ViewHolder构造函数中的setIsRecyclable(false)

现在RecyclerView的工作速度有点慢,但至少图像设置正确。

或者在onViewRecycled(ViewHolder holde)加载图像

您应该在使用滑行设置图像之前设置onBindViewHolder() imageView.setImageDrawable (null)onBindViewHolder()

将drawable设置为null可以解决问题。

希望能帮助到你!

这里的问题是,当您正在处理将要回收的视图时,您需要在绑定视图时处理所有可能的方案。

例如,如果要将ImageView添加到数据源位置0上的LinearLayout,那么,如果位置4不满足条件,则其视图很可能在绑定位置0时添加了ImageView。

您可以在您的内容中添加R.layout.images内容

R.layout.message_layout布局的R.id.placeholder并根据具体情况显示/隐藏占位符。

所以,你的onBindViewHolder方法将类似于:

 @Override public void onBindViewHolder(ViewHolder holder, int position) { Message item = mDataset.get(position); holder.title.setText(item.getTitle()); int numImages = item.getImages().size(); if (numImages > 0) { holder.placeholder.setVisivility(View.VISIBLE); ImageView image = (ImageView)holder.placeholder.findViewById(R.id.image); Glide.with(context) .load("http://img.androidcookie.com/android/test.png") .fitCenter() .into(image); }else{ holder.placeholder.setVisibility(View.INVISIBLE); } } 

我有同样的问题,我修复它像这样:

目标:onViewAttachedToWindow

 @Override public void onViewAttachedToWindow(Holder holder) { super.onViewAttachedToWindow(holder); StructAllItems sfi = mArrayList.get(position); if (!sfi.getPicHayatParking().isEmpty()) { holder.viewFliperMelk.addSlider(new TextSliderView(mContext.getApplicationContext()).image(T.GET_MELK_IMAGE + '/' + sfi.getPicHayatParking() + ".jpg").setScaleType(BaseSliderView.ScaleType.CenterCrop)); } if (!sfi.getPicSleepRoom().isEmpty()) { holder.viewFliperMelk.addSlider(new TextSliderView(mContext.getApplicationContext()).image(T.GET_MELK_IMAGE + '/' + sfi.getPicSleepRoom() + ".jpg").setScaleType(BaseSliderView.ScaleType.CenterCrop)); } if (!sfi.getPicSalonPazirayi().isEmpty()) { holder.viewFliperMelk.addSlider(new TextSliderView(mContext.getApplicationContext()).image(T.GET_MELK_IMAGE + '/' + sfi.getPicSalonPazirayi() + ".jpg").setScaleType(BaseSliderView.ScaleType.CenterCrop)); } if (!sfi.getPicNamayeStruct().isEmpty()) { holder.viewFliperMelk.addSlider(new TextSliderView(mContext.getApplicationContext()).image(T.GET_MELK_IMAGE + '/' + sfi.getPicNamayeStruct() + ".jpg").setScaleType(BaseSliderView.ScaleType.CenterCrop)); } } 

我也有同样的问题,并以下面的解决方案结束,它对我来说工作正常..

亲自使用此解决方案也可能适合您(将以下代码放在适配器类中) –

如果你正在使用Kotlin –

 override fun getItemId(position: Int): Long { return position.toLong() } override fun getItemViewType(position: Int): Int { return position } 

如果您使用的是JAVA –

  @Override public long getItemId(int position) { return position; } @Override public int getItemViewType(int position) { return position; }