ListView嵌套GridView显示多张图片出现图片重复、错乱、闪烁等问题

场景

为了实现一个订单下多个商品同时评价功能,列表分五种状态(非常满意,满意,一般,较差,不满意)展示,用一个listview,item中有一个GridView,GridView中放置最多五张图片;在listview上下滑动时会出现item中的图片重复、错乱、闪烁等问题。

出现错误

先讲我的错误。遇到问题后Google,参考了一些资料,都是提示要在外层listview的adapter上设置setTag(), 然后在内层GridView的adapter上整体和需要标记复用的imageView上setTag()。照此执行了,还是出错;后来在同事指点下,原来外层adapter中设置gridAdapter时只是在没有塞值时gridView.setVisibility(View.GONE),忘了要在有值的时候gridView.setVisibility(View.VISIBLE), 所以导致在复用的时候,没有了GridView可复用。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
//评价照片 
String evaluateImgs = item.getEvaluateDescriptionImgs();
MyGridView gridView = vh.getView(R.id.evaluate_image);
EvaluationViewGridAdapter gridAdapter;
if (!StringUtils.isEmpty(evaluateImgs)) {
//这里是否不需要判断包含`,`,`split`方法是否能自动判断,需要验证
if (evaluateImgs.contains(",")) {
String[] imgs = evaluateImgs.split(",");
gridAdapter = new EvaluationViewGridAdapter(imgs, mCallback.getContext());
gridView.setAdapter(gridAdapter);
//下面这句是我忘了加的
gridView.setVisibility(View.VISIBLE);
} else {
String[] imgs = new String[]{evaluateImgs};
gridAdapter = new EvaluationViewGridAdapter(imgs, mCallback.getContext());
gridView.setAdapter(gridAdapter);
//下面这句是我忘了加的
gridView.setVisibility(View.VISIBLE);
}
} else {
gridView.setAdapter(gridAdapter);
gridView.setVisibility(View.GONE);
}

教训:这个问题此前已经遇到过,真是不长记性,看来遇到一些常见问题还是要记录下来啊。例如写这个博客。

原因总结

为了提升listview性能,缓存复用了item(某行对应的View),ListView通过getView()获取每行的item。

滑动过程中,a. 如果某行item已经滑出屏幕,若该item不在缓存内,则put进缓存,否则更新缓存; b. 获取滑入屏幕的行item之前会先判断缓存中是否有可用的item,如果有,做为convertView参数传递给adapter的getView。

  • 行item图片显示重复:指当前行item显示了之前某行item的图片。
  • 行item图片显示错乱:指某行item显示了不属于该行item的图片。
  • 行item图片显示闪烁:上面b的情况,加载缓慢,还没加载完又滑到下一页,下一页某个item又加载出来了,所以导致图片快速覆盖,显示闪烁效果。

解决方法

第一步:ListView Adapter getView写法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
@Override
public View getView(int position, View convertView, ViewGroup parent) {
ViewHolder holder;
if (convertView == null) {
convertView = inflater.inflate(R.layout.list_item, null);
holder = new ViewHolder();
……
convertView.setTag(holder);
} else {
holder = (ViewHolder)convertView.getTag();
}
...
return convertView;
}

/**
* ViewHolder
*
* @author trinea@trinea.cn 2013-08-01
*/
private static class ViewHolder {
ImageView appIcon;
TextView appName;
TextView appInfo;
}

这里如果写的是convert()方法,则不需要写以上复用,因为父类中会做复用的事。

第二步: GridView gridAdapter getVIew写法

与上面写法类似;不过需要在用到图片的地方进行判断。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
@Override
public View getView(int position, View convertView, ViewGroup parent) {
ViewHolder holder;
if (convertView == null) {
convertView = inflater.inflate(R.layout.list_item, null);
holder = new ViewHolder();
……
convertView.setTag(holder);
} else {
holder = (ViewHolder)convertView.getTag();
}
...
/**
* 解决图片重复错乱闪烁的问题,例如
*/
//建立一个唯一标示,一般为item的相应String对象
String file = mListResult.get(position).getFile();
ImageAware imageAware =new ImageViewAware(holder.iv,false);
//首先得到要设置的GridView
holder.iv.setTag(file);
//判断tag存在否
if(holder.iv.getTag()!=null&&holder.iv.getTag().equals(file)){
imageLoader.displayImage(file,imageAware);
}

return convertView;
}

/**
* ViewHolder
*
* @author linking123.github.io 2017-03-29
*/
private static class ViewHolder {
ImageView appIcon;
TextView appName;
TextView appInfo;
}

一般情况下,走完以上两部可解决问题;解决不了的就要仔细检查一下,有没有像我一样的遗漏问题,小心啊,程序员们。

参考

感谢作者们的无私奉献,如有侵权,立马删除。



本文链接: http://home.meng.uno/articles/bc099606/ 欢迎转载!

© 2018.02.08 - 2020.06.02 Mengmeng Kuang  保留所有权利!

UV : | PV :

:D 获取中...

Creative Commons License