您的位置:首页 > 其它

ListView异步加载图片(解决图片混淆)

2013-09-19 23:38 399 查看
代码下载地址:

http://yunpan.cn/QWPJYQaihrXP3

由于工作原因,很久没有写博客了,工作中经常遇到ListView异步加载图片的问题,国内的网站上查了N多资料,几乎没有一个可用的,最根本的图片混淆问题都没有得到充分地解决。我的这个例子是借鉴Google
Code中的例子,删除了其中的没有必要的代码,完全可行。

该工程由ImageListActivity、ImageAdapter、ImageDownloader三个类构成。前两个类比较简单,这里不再赘述,下面我们就来分析一下ImageDownloader究竟是如何做到避免图片混淆的。

public void download(String url, ImageView imageView) {

resetPurgeTimer(); //清空集合

Bitmap bitmap = getBitmapFromCache(url);

if (bitmap == null) {

forceDownload(url, imageView);

} else {

cancelPotentialDownload(url, imageView);

imageView.setImageBitmap(bitmap);

}

}

通过研究以上代码可知,真正的下载代码是由forceDownload方法来完成,该方法如下:

private void forceDownload(String url, ImageView imageView) {

// State sanity: url is guaranteed to never be null in

// DownloadedDrawable and cache keys.

if (url == null) {

imageView.setImageDrawable(null);

return;

}

if (cancelPotentialDownload(url, imageView)) {

BitmapDownloaderTask task = new BitmapDownloaderTask(imageView)

DownloadedDrawable downloadedDrawable =

new DownloadedDrawable(task);

imageView.setImageDrawable(downloadedDrawable);

task.execute(url);

}

}

用便于理解的语言可以这样解释:

if(取消了之前该imageView对应的图片下载) {

1.创建下载图片的Task:BitmapDownloaderTask。

(让BitmapDownloaderTask 拥有imageView的引用,实现二者之 间的绑定,既该imageView一一对应一个BitmapDownloaderTask 对象)

2.初始化每一个ImageView为默认图片或颜色。(该默认图片就是DownloadedDrawable,该DownloadedDrawable拥有BitmapDownloaderTask 的引用,实现二者之间的绑定,既该DownloadedDrawable一一对应一个BitmapDownloaderTask 对象)

3.启动下载任务

}

有些童鞋对cancelPotentialDownload可能理解的不是很透彻。

private static boolean cancelPotentialDownload(String url,

ImageView imageView) {

BitmapDownloaderTask bitmapDownloaderTask =

getBitmapDownloaderTask(imageView);

if (bitmapDownloaderTask != null) {

String bitmapUrl = bitmapDownloaderTask.url;

if ((bitmapUrl == null) || (!bitmapUrl.equals(url))) {

bitmapDownloaderTask.cancel(true);

} else {

// The same URL is already being downloaded.

return false;

}

}

return true;

}

该方法对于,刚刚进入页面在没有做任何操作(尤其是滑动)时或者说对于listview中任何一个item首次加载时,当然是返回true,因为这个时候bitmapDownloaderTask为null.这时就会首次去执行下载图片的任务。

但是当我们向下滑动一屏,再向上滑动回之前那一屏时,这个时候bitmapDownloaderTask 已不再为null. 我们将bitmapDownloaderTask.url与参数中的url进行对比(这个时候注意:很明显参数中的url才是我们需要下载的url):如果不等,则停止正在下载的(因为这不是我们需要的),返回true;如果相等,则返回false,继续当前的图片下载任务。

这时候,又有童鞋问了,为什么以上imageView对应的url会变呢?

别着急,上下滑动listview,请查看ImageAdapter类中getView方法打印出来的Log, 如下图:





再看看getView方法:

public View getView(int position, View view, ViewGroup parent) {

if (view == null) {

view = new ImageView(parent.getContext());

view.setPadding(6, 6, 6, 6);

view.setMinimumHeight(150);

view.setMinimumWidth(150);

Log.v(TAG, "getView, ==========new========pos: "

+ position + " ,view: " + view);

} else {

Log.v(TAG, "getView, pos: " + position + " ,view: " + view);

}

imageDownloader.download(URLS[position], (ImageView) view);

return view;

}

怎么样,观察标记,有什么想法没。这说明当进入listView页面时,如手机一屏只能显示6个item,那么android系统就初始化6个view,当上下滑动时,android系统会重用这些已经创建好的ImageView,改变的仅仅是ImageView所显示的图片。

下面我们就对第一屏的最顶上的一个ImageView(以下取名为A)进行分析:

我们在第一屏首次构建了A,并绑定了一个BitmapDownloaderTask,当用手指下滑至A消失时,这时肯定会露出一个新的item,该item就会重用之前的A。这时,如果取出之前消失的A对应的task,我们对比task.url与参数中的url,如果不等,那么就暂停没有消失时正在下载的url(因为已经滑过去了,既不可见,再下载就没有意义了,再说优先级更高的应该是当前可见部分图片的下载)。

之后我们又调用了

DownloadedDrawable downloadedDrawable = new DownloadedDrawable(task);

imageView.setImageDrawable(downloadedDrawable);

在下载图片之前,需要先给ImageView设置默认的图片.以上两句很重要,否则就不能做到真正的图片混淆。

我查了很多资料,国内资料上做的最好的也就是该例子去掉以上两句的效果,会先闪一下错误的图片,而后再显示正确的图片。

以下是我收录的比较好的更新ListView的文章,在这里分享给大家:

1. code
google(最好的实现实例)
2. Android
ListView 异步加载图片 再优化
3. 滑动过程中不加载图片
4. 更新ListView的一个Item
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: