ListView异步加载图片(解决图片混淆)
代码下载地址:https://115.com/file/e75ks6jj#ImageLoader_test.zip
由于工作原因,很久没有写博客了,工作中经常遇到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
最后更新:2017-04-02 22:14:28