android 异步图片加载 开源,异步加载图片BitmapFun分析

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

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

开源项目地址

项目简介

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

项目分析

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

ImageWorker $ loadImage

76a134227a5c5e8865ac8f2c22825499.png

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

f2724aa2eb333be7bfb50efebcd7c33d.png

9af324c7b008ce4f44e20139c478aec3.png

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

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

072cb319080207b526d7ee3ac0790d5d.png

先调用了cancelPotentailWork方法:

6072b08785f51d2ec99af5c1e820d0bf.png

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

0fa743092a903fb2c3153cdeaf0eeafd.png

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

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

BitmapWorkerTask的data是什么?

0f30f74e9a9b7ac1d4960ff0068fca81.png

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

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

88aa9412a2326226710fc18280d5d766.png

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

首先创建一个Task,

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

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

最后执行这个BitmapWorkerTask。

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

84b8a1979a0f25f09bbd56d272750fee.png

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

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

c97dc7467e42a9ade832814964680f75.png

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

主要处理图片的过程:

83a20ae464b5cba2dd59b65355956652.png

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

7ba233151277b550f15aa68097460f48.png

在IamgeFetcher中也有实现:

caeb37b415007b759430824496b2d397.png

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

Task结束之后,执行onPostExcute

88bc1f00c5de88548ea054d4ffa8f8fb.png

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

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

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

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

a09da7f0ca8ef37f65dbe0eadf03c162.png

主要就是保存了一个task。

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

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

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

接下来就是缓存的实现:

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

4f8f9ea9c462290446f9ce53c2d6cded.png

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

初始化的过程:

84504c12e6756b25cb957c4dea891c4e.png

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

7de103b3713c4ff9553ec049186967df.png

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

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

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值