ListView图片错乱原因分析

        

先来看一段代码:

@Override
public View getView(finalint position, ViewconvertView, ViewGroup parent) {
    ViewHolder holder;
    if (convertView== null) {
        convertView = mInflater.inflate(R.layout.item, null);
        holder = new ViewHolder();
        holder.appIcon = (ImageView) convertView.findViewById(R.id.appIcon);
        holder.name = (TextView) convertView.findViewById(R.id.name);
        holder.size = (TextView) convertView.findViewById(R.id.size);
        holder.chose = (CheckBox) convertView.findViewById(R.id.chose);
        convertView.setTag(holder);
    } else
        holder = (ViewHolder) convertView.getTag();
    MyFile myFile = fileList.get(position);
    Drawable icon = myFile.icon;
    if (icon!= null)
        holder.appIcon.setImageDrawable(myFile.icon);

    holder.chose.setChecked(myFile.isChose);
    holder.name.setText(myFile.name);
    holder.size.setText(myFile.formatSize);
    holder.chose.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
        @Override
        public void onCheckedChanged(CompoundButton compoundButton, boolean b) {
            fileList.get(position).isChose = b;
        }
    });
    return convertView;
}

当你执行下去会发现出现图片错乱的问题,但是当你把if (icon != null)这段注释掉,你会发现突然好了,这是什么原因呢,下面就来分析一下:

a)     ListView的复用机制

         i.   ListView是我们经常使用的一个控件,虽然说都会用,但是却并不一定完全清楚ListView的复用机制,虽然在Android 5.0版本之后提供了RecycleView去替代ListView和GridView,提供了一种插拔式的体验,也就是所谓的模块化。本篇主要针对ListView的复用机制进行探讨,因此就不提RecycleView。 

         ii.  首先需要说一下RecycleBin的基本原理,这个类也是实现复用的关键类。接着我们需要明确ActiveView的概念,ActiveView其实就是在UI屏幕上可见的视图(onScreenView),也是与用户进行交互的View,那么这些View会通过RecycleBin直接存储到mActivityView数组当中,以便为了直接复用,那么当我们滑动ListView的时候,有些View被滑动到屏幕之外(offScreen) View,那么这些View就成为了ScrapView,也就是废弃的View,已经无法与用户进行交互了,这样在UI视图改变的时候就没有绘制这些无用视图的必要了。他将会被RecycleBin存储到mScrapView数组当中,但是没有被销毁掉,目的是为了二次复用,也就是间接复用。当新的View需要显示的时候,先判断mActivityView中是否存在,如果存在那么我们就可以从mActivityView数组当中直接取出复用,也就是直接复用,否则的话从mScrapView数组当中进行判断,如果存在,那么二次复用当前的视图,如果不存在,那么就需要inflate View了。

        iii .   可能很多读者都不太明白直接复用到底是怎么个过程,举个例子,比如说我们ListView一页可以显示10条数据,那么我们在这个时候滑动一个Item的距离,也就是说把position = 0的Item移除屏幕,将position = 10 的Item移入屏幕,那么position = 1的Item是不是就直接能够从mActivityView数组中拿到呢?这是可以的,我们在第一次加载Item数据的时候,已经将position = 0~9的Item加入到了mActivityView数组当中,那么在第二次加载的时候,由于position = 1 的Item还是ActivityView,那么这里就可以直接从数组中获取,然后重新布局。这里也就表示的是Item的直接复用。简单来说就是如果对应的position的item在当前显示的界面就相当于移动一下位置。

b)     上面是理论基础部分,接着结合代码分析一下,首先我们代码复用了“convertView”,这个就是起因,正如上面介绍的,“convertView”是来自于mScrapView或者mActivityView数组,因此每次滑动时最上面一个item会消失在屏幕中,最下面一个会出现在屏幕中。然后ListView会复用上一个消失的item,这个item的各种值此刻还是保留的,接着就是上面问题的解释了,为什么去掉了if (icon!= null)这段就不会图片错乱了。因为有这个条件我们当前的item就可能不会重新设置ImageView的图片,导致它还是上一次的图片

c)     因此有个结论,为了防止图片错乱,有两个办法,一个是基础部分,就是item的每个控件都要重新赋值,不管值是否为空;另一个就是设置Tag,这种是针对异步加载图片情况处理的

猜你喜欢

转载自blog.csdn.net/u012292247/article/details/70910278
今日推荐