异步加载图片BitmapFun分析

博客地址:http://my.oschina.net/lifj/blog/313866

-------- 2014年8月19日 BY 拉风的道长

开源项目地址

https://developer.android.com/training/displaying-bitmaps/index.html

 

项目简介

如果图片资源是静态的,当我们要在View上显示图片时,只需要简单的将图片赋值给ImageView就可以了,但如果需要浏览网络上的图片时该如何做呢?有可能图片很大,有可能网速很慢并且不稳定,这种情况下该如何增加用户体验。Android官方的BitmapFun示例程序已经给了我们很好的解决方法 - 其实万变不离其中,还是采用了提升性能的两种常用方法:异步和缓存。

 

项目分析

下载源码之后(最新的代码可能和本文分析的代码不同,但是思路应该没有变),用Eclipse 打开,开始分析吧。从哪里入手分析呢?从使用方法入手!按照使用方法,从头到尾顺藤摸瓜走一遍。这样,基本上就能把整个代码逻辑走遍了。

 

ImageWorker $ loadImage

先从ImageCache中获取图片。ImageCache是什么?是我们缓存的主要类:包括内存和磁盘。

 

 

 这里主要从mMemoryCache获取图片,然后返回。

上面从ImageCache中获取缓存之后,如果不为空,就直接设置图片。如果为空,就进入else

 

 先调用了cancelPotentailWork方法:

 

 先获取BitmapWorkerTask,看看是不是需要取消。

 

 

这里,获取BitmapWorkerTask时,从AnsyncDrawable中获取这个task。

获取到这个taskt,然后通过BitmapWorkerTask的data来判断:如果为空或者新旧不相等,就取消。然后返回ture。

BitmapWorkerTask的data是什么?

 

 

BitmapWorkerTask是AnsncTask。data是执行BitmapWorkerTask时传过来的第一个参数。

在哪里创建的?其实就是在else中创建的:

 

 

如果是需要取消之前的任务,则进入到else里面。这里,就是启动一个新的下载(读取磁盘或者网络)过程。

首先创建一个Task,

然后创建一个AsyncDrawable。在创建这个drawable的时候,就把task传了过去。这样,在上面判断是不是需要取消的时候,就能获取到对应的task了。

接着把这个asyncDrawable设置到imgeView中。

最后执行这个BitmapWorkerTask。


可以看出:主要的方法就是BitmapWorkerTask。

 

总体流程是:先从diskCache中读取,如果没有,就再调用processBitmap。最终,都会把这个图片添加到imageCache中。这也就是一开始loadImage时,从imageCache中获取的来源。

 

从ImageCache中读取的条件是:缓存不为空,任务没有被取消,获取和任务绑定的ImageView不为空,以及没有被提前取消。

 

获取绑定的imageview 是防止Imageview被重新设置了task,然后导致两次绑定的task不同。

 

主要处理图片的过程:

 

processBitmap是抽象方法,具体的实现类是在ImageResizer中。

 

 

在IamgeFetcher中也有实现:

 

 

这里先放一下吧。回到之前的。

Task结束之后,执行onPostExcute

 

 

这里又一次检查imageview的匹配。

其实有时候,你会惊讶于谷歌的人思维真紧密,这边都想到要判断一下。

就我个人的经验,其实,有时候,不是想起来的,不是思维缜密。而是出现了bug,然后加上的这些判断。所以,有时候读源码,看到别人的判断感觉很没有必要或者说很细,其实都是bug的补丁。

Task就是这样,AsyncDrawable也是很重要的一个类:

 

主要就是保存了一个task。

其实这里保证了图片和ImageView的一致性,防止图片错乱:

Task绑定住ImageView,ImageView绑定住AsyncDrawable,AsyncDrawable绑定住Task。

当设置图片的时候(在Task中设置图片):从绑定的ImageView中获取AsyncDrawable,再获取绑定的Task。然后比较这两个task是不是相同。为什么可以这么做呢?当一个ImageView要重新加载图片的时候,会给ImageView重新设置AsyncDrawable。所以,即使重用了,如果ImageView对应的Task不同,那么就说明图片已经修改了,这次的Task就不应该设置图片了。

接下来就是缓存的实现:

缓存分为磁盘缓存和内存缓存。

 

LRU是Least Recently Used 近期最少使用算法。也就是:当内存(或者磁盘)容量不够时,把最近使用最少的内容去除掉,从而腾出空间增加新内容。

初始化的过程:

 

先创建diskCache,然后创建memoryCache。主要的参数涉及到一个memSize,定义了cache的大小。内存cache的创建比较简单,主要是diskCache:

 

上面的代码是创建一个新的diskCache。通过一个dir的地址,创建一个文件夹,同时判断可用空间是不是超过最大的memSize。这决定了diskCache是否创建成功。

diskCache和memoryCache的放置数据,都是key-value型的,这个没什么好讲的。

 

转载于:https://my.oschina.net/lifj/blog/313866

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值