ListView中子view复用机制的实现原理以及图片错位的解决方案

版权声明:转载必须注明本文转自郭子轩的博客 https://blog.csdn.net/gpf1320253667/article/details/52493441

ConvertView复用原理图:借助于RecycleBin(回收站)实现复用;

RecycleBin的作用:对子View进行回收利用。


移出屏幕的ImageView控件会进入到RecycleBin当中,而新进入屏幕的元素则会从RecycleBin中获取ImageView控件。

图片错位原因:
如果我们只是简单显示list中数据,而没用convertview的复用机制和异步操作,就不会产生图片错位;重用convertview但没用异步,也不会有错位现象。

RecycleBin工作原理解释:

ListView会把那些移出屏幕的子view放入到RecycleBin中存起来,就像把暂时无用的资源放到回收站一样。

当 ListView的底部需要显示新的View的时候,会从RecycleBin中取出一个子View,将其作为convertView参数传递给 Adapter的getView方法,从而达到View复用的目的,这样就不必在Adapter的getView方法中执行LayoutInflater.inflate()方法了。

RecycleBin中有两个重要的View数组,分别是 mActiveViews和mScrapViews。这两个数组中所存储的View都是用来复用的,只不过mActiveViews中存储的是 OnScreen的View,这些View很有可能被直接复用;而mScrapViews中存储的是OffScreen的View,这些View主要是用 来间接复用的。


产生错位的原因:ConvertView复用+异步同时使用时产生。

每当有新的元素进入界面时就会回调getView()方法,而在getView()方法中会开启异步请 求从网络上获取图片,注意网络操作都是比较耗时的,也就是说当我们快速滑动ListView的时候就很有可能出现这样一种情况,某一个位置上的元素进入屏 幕后开始从网络上请求图片,但是还没等图片下载完成,它就又被移出了屏幕。这种情况下会产生什么样的现象呢?根据ListView的工作原理,被移出屏幕 的控件将会很快被新进入屏幕的元素重新利用起来,而如果在这个时候刚好前面发起的图片请求有了响应,就会将刚才位置上的图片显示到当前位置上,因为虽然它们位置不同,但都是共用的同一个ImageView实例,这样就出现了图片乱序的情况。

但是还没完,新进入屏幕的元素它也会发起一条网络请求来获取当前位置的图片,等到图片下载完的时候会设置到同样的ImageView上面,因此就会出现先显示一张图片,然后又变成了另外一张图片的情况,那么刚才我们看到的图片会自动变来变去的情况也就得到了解释。

解决方法:
对imageview设置tag,并预设一张图片。
向下滑动后,item6显示,item0隐藏。但由于item0是第一次进来就显示,所以一般情况下,item0都会比item6先下载完,但由于此时可 见的item6的tag,和隐藏了的item0的url不匹配,所以就算item0的图片下载完也不会显示到item6中,因为tag标识的永远是可见图 片中的url。

关键代码:

// 给 ImageView 设置一个 tag

holder.img.setTag(imgUrl);

// 预设一个图片

holder.img.setImageResource(R.drawable.ic_launcher);

 

// 通过 tag 来防止图片错位

if (imageView.getTag()!= null && imageView.getTag().equals(imageUrl)) {

    imageView.setImageBitmap(result);

}

 

或者使用findViewWithTag()方法。

猜你喜欢

转载自blog.csdn.net/gpf1320253667/article/details/52493441
今日推荐