目前第三方的图片加载库很多,例如:universal-image-loader,Volley等,今天我们来写一个简单的图片加载库实现图片网络下载缓存。
首先先了解一下图片加载用什么方式,通常我们从网络加载图片的时候希望加载的图片优先从本地缓存获取,本地没有就从网络下载再缓存到本地,这样可以减少网络访问的开销和提高图片加载的速度,从而增加用户体验。
本地的缓存资源可以保存在内存和本地文件中,那么图片的加载流程优先级由高到低是:从内存中获取--从本地缓存文件中获取--从网络获取。
我们内存缓存使用的是 LruCache,文件缓存使用的是DiskLruCache 或者 File 类。
注意:以前也有使用软引用和弱引用实现图片缓存,但这种方式从API 9 开始起不了作用了。垃圾回收器会更倾向于回收持有软引用或弱引用的对象,这让软引用和弱引用变得不再可靠。
一、LruCache
这个类是android 3.1 提供的,之前的旧版本需要使用android-support-v4 支持库才能使用。LruCache使用一个LinkedHashMap简单的实现内存的缓存,没有软引用,都是强引用。
下面看看LruCache怎样使用
(1)新建LruCache对象
mMemoryCache = new LruCache<String, Bitmap>(maxCacheSize) {
// 必须重写此方法,来测量Bitmap的大小
@Override
protected int sizeOf(String key, Bitmap value) {
return value.getRowBytes() * value.getHeight();
}
};
LruCache的构造方法传入的参数是指定缓存的大小,如果添加的数据大于设置的最大值,就删除最先缓存的数据来调整内存。重写的方法sizeof是计算图片的大小。
(2)添加图片缓存
//添加Bitmap到内存缓存
mMemoryCache.put(key, bitmap);
key的值用于取出对应的图片缓存用的。
(3)获取图片缓存
//从内存缓存中获取一个Bitmap
mMemoryCache.get(key);
LruCache的方法不多,用的最多的是添加和获取的方法了,总的来说LruCache 的使用还是比较简单的。
二、DiskLruCache
DiskLruCache 硬盘缓存,DiskLruCache 并不在 Android API 中,我们需要在网上下载源码文件,把源码文件放到我们的工程里,记得改源码文件的包路径。
添加DiskLruCache 类到工程里面之后,看看它是怎么用的
(1)创建 DiskLruCache
DiskLruCache的创建需要调用它的静态方法open
public static DiskLruCache open(File directory, int appVersion, int valueCount, long maxSize);
该方法的参数有4个:
directory ---- 数据的缓存路径
appVersion ---- 当前应用程序的版本号
valueCount ---- 指定同一个key可以对应多少个缓存文件,基本都是传1
maxSize ---- 最多可以缓存多少字节的数据
例子:
/**
* 初始化 DiskLruCache
*/
private void initDiskLruCache() {
try {
PackageInfo info = context.getPackageManager().getPackageInfo(context.getPackageName(), 0);
try {
diskLruCache = DiskLruCache.open(new File(getCacheStoragePath()), info.versionCode, 1,
config.disCacheSize);
} catch (IOException e) {
e.printStackTrace();
}
} catch (NameNotFoundException e) {
e.printStackTrace();
}
}
(2)获取缓存文件资源
DiskLruCache.Snapshot snapShot = diskLruCache.get(subUrl);
if (snapShot != null) {
FileInputStream fileInputStream = (FileInputStream) snapShot.getInputStream(0);
// 从流中转成Bitmap对象
bitmap = BitmapFactory.decodeStream(fileInputStream);
...
} else {
Log.i("load", "手机存储中没有");
}
(3)保存缓存文件
先获取 DiskLruCache.Editor 对象
DiskLruCache.Editor editor = diskLruCache.edit(key);//参数 key 是缓存文件的文件名
if (editor != null) {
//从Editor 获取缓存的输出流
OutputStream outputStream = editor.newOutputStream(0);
//把数据保存成文件
bitmap.compress(config.compressFormat, config.imageQuality, outputStream);
//commit 提交
editor.commit();
...
}
其它的操作:
diskLruCache.delete(); 删除全部缓存文件
diskLruCache.flush();
diskLruCache.close(); 关闭缓存
diskLruCache.remove(key); 移除key对应的缓存
diskLruCache.size() 缓存的大小
diskLruCache.getDirectory() 缓存目录
diskLruCache.isClosed() 缓存是否关闭
三、设计图片加载库
设计的目标:
(1)加载流程 :从内存中获取--从本地缓存文件中获取--从网络获取
(2)线程池
(3)LruCache 负责内存缓存,DiskLruCache 负责硬盘缓存。
具体的源码: