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

简介:
代码下载地址:
http://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
相关文章
|
开发工具 Android开发
解决bug:运行项目时报异常 “Can't create handler inside thread that has not called Looper.prepare()”
解决bug:运行项目时报异常 “Can't create handler inside thread that has not called Looper.prepare()”
1536 0
|
Android开发 UED 开发者
Android Activity启动模式详解
Android Activity启动模式详解
525 0
|
Android开发
Android经典实战之Textview文字设置不同颜色、下划线、加粗、超链接等效果
本文介绍了 `SpannableString` 在 Android 开发中的强大功能,包括如何在单个字符串中应用多种样式,如颜色、字体大小、风格等,并提供了详细代码示例,展示如何设置文本颜色、添加点击事件等,助你实现丰富文本效果。
897 4
|
JSON 前端开发 JavaScript
JSON.parse()详解
JSON.parse()详解
766 1
|
移动开发 编解码 缓存
mPaas H5离线包优化指南
在移动互联网时代的今天,市场上绝大多数终端App都在使用H5展示页面,且随着终端技术迭代更新和市场多变性,H5页面在App中的占比越来越重要。同时也暴露出一个所有App的共性问题,即性能优化。同样的H5页面的性能优化也是重点问题。 在mPaaS团队中虽然已将H5页面资源等打包做离线包了,但在复杂的客户环境、开发环境、市场环境下,客户端的H5离线包仍有性能优化问题,这里整理简单了集团下对H5离线包的优化策略方案,以供参考。
3254 0
mPaas H5离线包优化指南
|
前端开发 Android开发
Android压缩图片文件大小到限定值以下
开发中会有用户头像上传的需求,为了节省流量,一般上传接口都会限制图片大小,比如1M。但是随着手机像素越来越高,这个限制很容易达到,所以需要客户端在上传图片进行压缩操作。 先说一下思路:主要是等比缩小图片文件,辅之使用Bitmap#compress进行压缩。
|
存储 开发工具 Android开发
Android 10.0后创建文件createNewFile()和创建文件夹mkdirs()均失败解决方案
Android 10.0后创建文件createNewFile()和创建文件夹mkdirs()均失败解决方案
998 0
|
缓存 前端开发 Java
java.lang.RuntimeException: Canvas: trying to use a recycled bitmap android.graphics.Bitmap@358df999
java.lang.RuntimeException: Canvas: trying to use a recycled bitmap android.graphics.Bitmap@358df999
|
Android开发 编解码
Android应用开发中三种常见的图片压缩方法
版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/u010046908/article/details/52368551 Android应用开发中三种常见的图片压缩方法,分别是:质量压缩法、比例压缩法(根据路径获取图片并压缩)和比例压缩法(根据Bitmap图片压缩)。
1108 0