這個bug可以說是折磨了我很久了庆揪,問了人境析,查了博客,最后找到了答案咆槽。
首先要搞明白RecyclerView中的ViewHolder的復用機制是什么陈轿,在,以及由于復用機制和請求網(wǎng)絡(luò)mix在一起之后會發(fā)生哪些可能的事故罗晕,強烈推薦一個好文:
他的博客取來的圖片
總結(jié)一下就是:
- RecyclerView用的是我們自定義的內(nèi)部類ViewHolder來復用的济欢,也就是復用的是ViewHoler
- 當屏幕下滑,item1滑出可視區(qū)域小渊,將item1的ViewHolder對象給item8復用法褥,那么此時item1中ViewHolder對象中持有的變量都是item1的。
- item1中的ViewHolder對象酬屉,在onBindViewHolder(MyViewHolder holder, int position)方法中對holder進行更新半等,但是如果在這里調(diào)用glide去從url加載圖片到holder中的imageView對象的話揍愁,就有可能因為網(wǎng)絡(luò)延遲,導致圖片加載不出來杀饵,那么item8就會先顯示item1的圖片莽囤,過一會延遲之后,顯示正確的item8該顯示的圖片
上面博客加載圖片用的是AsynTask切距,我用的是Glide框架朽缎,ViewHolder中3個TextView,一個ImageView,按照那個思路,我的處理方法如下:
@Override
public void onBindViewHolder(MyViewHolder holder, int position) {
if (holder == null) {
return;
}
holder.tvDesc.setText(resultsBeanList.get(position).getDesc());
holder.tvPublishedAt.setText(timeParse.getTime(resultsBeanList.get(position).getPublishedAt()));
Object who = resultsBeanList.get(position).getWho();
if (who != null) {
holder.tvWho.setText((String) who);
}else {
//防止ViewHolder復用導致上一個tvWho的內(nèi)容遺留
holder.tvWho.setText("");
}
//處理imageView--------------
List<String> imagesUrl = resultsBeanList.get(position).getImages();
if (imagesUrl == null) {
//當ViewHolder復用的時候谜悟,如果當前返回的圖片url為null话肖,為了防止上一個復用的viewHolder圖片
//遺留,要clear并且將圖片設(shè)置為空葡幸。
Glide.with(fragment).clear(holder.ivImage);
holder.ivImage.setImageDrawable(null);
holder.ivImage.setTag(R.id.image_tag, position);
return;
}
Object tag=holder.ivImage.getTag(R.id.image_tag);
if (tag!=null&&(int) tag!= position) {
//如果tag不是Null,并且同時tag不等于當前的position最筒。
//說明當前的viewHolder是復用來的
//Cancel any pending loads Glide may have for the view
//and free any resources that may have been loaded for the view.
Glide.with(fragment).clear(holder.ivImage);
}
String url = imagesUrl.get(0);
Glide.with(fragment)
.load(url + "?imageView2/0/w/100")
.apply(options)
.into(holder.ivImage);
//給ImageView設(shè)置唯一標記。
holder.ivImage.setTag(R.id.image_tag, position);
}
至此蔚叨,不再圖片混亂床蜘。