教你写Android ImageLoader框架之图片缓存 (完结篇)
在教你写Android ImageLoader框架系列博文中,我们从基本架构到具体实现已经更新了大部分的内容。今天,我们来讲最后一个关键点,即图片的缓存。为了用户体验,通常情况下我们都会将已经下载的图片缓存起来,一般来说内存和本地都会有图片缓存。那既然是框架,必然需要有很好的定制性,这让我们又自然而然的想到了抽象。下面我们就一起来看看缓存的实现吧。
缓存接口
在教你写Android ImageLoader框架之图片加载与加载策略我们聊到了Loader,然后阐述了AbsLoader的基本逻辑,其中就有图片缓存。因此AbsLoader中必然含有缓存对象的引用。我们看看相关代码:
/**
* @author mrsimple
*/
public abstract class AbsLoader implements Loader {
/**
* 图片缓存
*/
private static BitmapCache mCache = SimpleImageLoader.getInstance().getConfig().bitmapCache;
// 代码省略
}
1
2
3
4
5
6
7
8
9
10
11
12
AbsLoader中定义了一个static的BitmapCache对象,这个就是图片缓存对象。那为什么是static呢?因为不管Loader有多少个,缓存对象都应该是共享的,也就是缓存只有一份。说了那么多,那我们先来了解一下BitmapCache吧。
public interface BitmapCache {
public Bitmap get(BitmapRequest key);
public void put(BitmapRequest key, Bitmap value);
public void remove(BitmapRequest key);
}
1
2
3
4
5
6
7
8
9
BitmapCache很简单,只声明了获取、添加、移除三个方法来操作图片缓存。这里有依赖了一个BitmapRequest类,这个类代表了一个图片加载请求,该类中有该请求对应的ImageView、图片uri、显示Config等属性。在缓存这块我们主要要使用图片的uri来检索缓存中是否含有该图片,缓存以图片的uri为key,Bitmap为value来关联存储。另外需要BitmapRequest的ImageView宽度和高度,以此来按尺寸加载图片。
定义BitmapCache接口还是为了可扩展性,面向接口的编程的理念又再一次的浮现在你面前。如果是你,你会作何设计呢?自己写代码来练习一下吧,看看自己作何考虑,如果实现,这样你才会从中有更深的领悟。
内存缓存
既然是框架,那就需要接受用户各种各样的需求。但通常来说框架会有一些默认的实现,对于图片缓存来说内存缓存就其中的一个默认实现,它会将已经加载的图片缓存到内存中,大大地提升图片重复加载的速度。内存缓存我们的策略是使用LRU算法,直接使用了support.v4中的LruCache类,相关代码如下。
/**
* 图片的内存缓存,key为图片的uri,值为图片本身
*
* @author mrsimple
*/
public class MemoryCache implements BitmapCache {
private LruCache mMemeryCache;
public MemoryCache() {
// 计算可使用的最大内存
final int maxMemory = (int) (Runtime.getRuntime().maxMemory() / 1024);
// 取4分之一的可用内存作为缓存
final int cacheSize = maxMemory / 4;
mMemeryCache = new LruCache(cacheSize) {
@Override
protected int sizeOf(String key, Bitmap bitmap) {
return bitmap.getRowBytes() * bitmap.getHeight() / 1024;