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
相关文章
|
缓存 Java Android开发
Android使用LruCache、DiskLruCache实现图片缓存+图片瀑布流
**本文仅用于学习利用LruCache、DiskLruCache图片缓存策略、实现瀑布流和Matix查看大图缩放移动等功能,如果想用到项目中,建议用更成熟的框架,如[glide]
130 0
|
XML Android开发 数据格式
Android Glide加载网络图片不显示,但用网页打开又正常显示
Android Glide加载网络图片不显示,但用网页打开又正常显示
622 0
Android Glide加载网络图片不显示,但用网页打开又正常显示
|
Java Android开发 UED
android中ListView异步加载图片时的图片错位问题解决方案
android中ListView异步加载图片时的图片错位问题解决方案
|
缓存 Android开发
Android笔记:使用Glide加载图片刷新时会闪烁
Android笔记:使用Glide加载图片刷新时会闪烁
1093 0
|
前端开发 Android开发 应用服务中间件
Android高级控件(二)——SurfaceView实现GIF动画架包,播放GIF动画,自己实现功能的初体现
<div class="markdown_views"> <h1 id="android高级控件二surfaceview实现gif动画架包播放gif动画自己实现功能的初体现">Android高级控件(二)——SurfaceView实现GIF动画架包,播放GIF动画,自己实现功能的初体现</h1> <hr> <blockquote> <p>写这个的原因呢,也是因为项目中用到
2987 0