Android中的ListView是一个非常常用的控件,但是它却并不像想象中的那么简单。特别是当你需要在ListView中展示大量网络图片的时候,处理不好轻则用户体验不佳,重则OOM,异步线程丢失或者图片错位。
关于其中的OOM和异步线程丢失的问题,是一个很庞大的话题,本人能力有限,无法说清,只有遇到的时候临时找原因,想办法解决了。但是对于图片错位,却是可以避免的,今天我们就来说一说ListView异步加载图片中的图片错位问题。
为什么会出现图片错位的问题呢?一般是重用了convertView导致的。如果你重用了convertView,此时convertView中的ImageView的id值是相等的,而我们在设置ImageView的图片时,是根据id来设置的,此时就出现了图片错位问题。这里童鞋们可以自己去测试一下,不重用convertView,也就是每次getView的时候,都使用findViewById(R.id.xx)去得到每一个Item的ImageView,异步下载图片的方法也只是简单的开一个AsyncTask执行下载。在这种情况下,图片一般是不会产生错位的。原因很简单,认真读一读前面的内容就明白了。但是你如果真的在使用这种方法来使用getView的话,并且图片量比较大的时候,你程序的性能肯定不会好到哪里去了。因此,重用convertView还是很有必要的。
这里需要注意,convertView是否为null会根据ListView的中布局标签值的不同有区别,具体的内容请参见这两篇文章:
android listview 连续调用 getview问题分析及解决
[Android] ListView中getView的原理+如何在ListView中放置多个item
这也就是说,某种情况下你界面中的第一张和第二张图片之间就有可能产生错位,因为有可能第二个可见的ImageView就来自共用的convertView。
处理像这种图片的异步加载的问题,我们的一般思路是:下载的图片根据图片名称存入到SDCard中,最新加载的图片存入到软引用中。我们在getView中给ImageView设置图片的时候,首先根据url,从软引用中读取图片数据;如果软引用中没用,则根据url(对应图片名)从SDCard中读取图片数据;如果SDCard中也没有,则从网络上下载图片,在图片下载完成后,回调主线中的方法更新ImageView。下面我们就照着上面的思路,先把程序整出来再说吧。先看下效果图:
布局文件有两个,很简单,一个表示ListView(main.xml),一个表示ListView中的元素(single_data.xml),如下:
[java] view plaincopy
- xmlns:tools="http://schemas.android.com/tools"
- android:layout_width="fill_parent"
- android:layout_height="fill_parent"
- android:orientation="vertical"
- android:background="@android:color/darker_gray"
- tools:context=".MainActivity" >
- android:layout_width="fill_parent"
- android:layout_height="wrap_content"
- android:cacheColorHint="@null"
- android:id="@+id/listview"
- />
[java] view plaincopy
- android:layout_width="fill_parent"
- android:layout_height="wrap_content"
- android:background="@android:color/white"
- >
- android:layout_width="150dp"
- android:layout_height="150dp"
- android:scaleType="fitXY"
- android:id="@+id/image_view"
- android:background="@drawable/ic_launcher"
- />
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_alignTop="@id/image_view"
- android:layout_alignBottom="@id/image_view"