【AndroidUniversalImageLoader】源码学习之缓存模块(磁盘缓存,内存缓存)

来源:互联网 发布:算法导论 微盘 编辑:程序博客网 时间:2024/06/04 19:17

PS:最近在梳理关于Android图片加载的知识,期间接触了AFinal的FinalBitmap模块及UniversalImageLoader(后面简称UIL)等两个开源项目。发现UniversalImageLoader对于图片的加载来说还是比AFinal更专业一点。UniversalImageLoader实现了大量的策略模式让图片加载的配置化十分丰富,能够应对各类需求。


阅读本文前你必须看的文章:

OOM:http://blog.csdn.net/zenip/article/details/8699286


一些基础概念:

图片缓存:一般用于保存经过缩放,无损压缩后的图片。 理论上内存缓存属于第一层缓存,而硬盘则为第二层次的缓存缓存,用于提高图片的浏览效率以增强用户体验。


缓存策略的设计关键

缓存策略是一块独立而且通用的逻辑。不应该与具体的读写操作,图片转化操作等组合在一起,通用和简单是缓存策略应该思考的问题。

UIL提供了简约缓存获取接口,基本上就是一个Map映射的函数操作:

clear函数:

get(K)函数

keys函数

put函数

remove()函数


缓存策略的基础算法:

UIL提供了一些经典的缓存策略如:FIFO(先进先出),LRU(最近使用优先),指定生命周期(LimitedAge)。这些算法具体的应用场景看需求而定。FIFO适用于ViewPager的往前切换,而LRU适用于一些用户频繁打开的图片(例如:QQ聊天你总是跟某些人聊,那么LRU策略非常适合)


UIL的内存缓存(MemoryCache)

以下是内存缓存的代码结构,通过继承来实现不同的规则。这是一个比较经典的策略模式。

WeakMemoryCache:采用弱引用缓存(PS:弱引用在GC时就会被回收)。

LruMemoryCache:采用强引用(StringReference)来引用内存。这是UIL默认使用的,只要图片不是太大和分配太频繁。这个使用一般没问题,假设用了这个策略还经常OOM。那建议使用WeakReference,或者修改相关参数设定(UIL的github简介https://github.com/nostra13/Android-Universal-Image-Loader讲得很清楚,感兴趣的同学自己上去看吧)。

LimitedMemoryCache:有四个子类分别代表四种内存策略,用的都是弱引用。




UIL的磁盘缓存:

UIL的磁盘缓存与AFinal不同,前者使用不同文件来存储不同的图片缓存,而后者使用BlobCache单个二进制文件来存储所有的图片缓存。

UIL的磁盘缓存模块不涉及具体文件的读写操作。但负责了文件的删除与缓存管理。代码逻辑清晰明了,简单易懂。


UIL磁盘缓存代码的一些小知识点:

AtomicInteger:原子化整形,采用volatile关键字实现,一般用于线程并发计数。UIL中用于处理总体cacheSize的线程同步问题,效率比synchronized高很多。(但是不得不吐槽,UIL的实现不无法保证DiscCache不超过上限,详见另一篇文章(AtomicInteger的误用)。

Collections.synchronizedMap:将HashMap增加线程同步机制,保证线程安全。


以下是UIL的磁盘缓存类图,可以看出是一个比较清晰的策略模式:

DiscCacheAware:接口。

BaseDiscCache:集成了一个重命名策略

LimitedDiscCache:提供可指定文件大小上限的磁盘缓存,采用的是LRU算法(最近使用的最优先)

LimitedAgeDiscCache:提供可指定缓存文件存活时长得缓存,采用的也是LRU算法(最近使用会更新重新计算)

UnlimitedDiscCache:提供无限制的大小上限的磁盘缓存。(!!这个实现非常有趣,直接通过覆盖BaseDiscCache的方法便实现了这种策略)

FileCountLimitedDiskCache与TotalSizeLimitedDiskCache:也是通过继承实现了不同的策略。




总结

缓存模块的设计追求简单,通用独立。这一点UIL做得十分不错,通过定义统一的接口,实现不同的内存策略。



0 0
原创粉丝点击