前言
本篇主要仿照Glide完成图片三级缓存(内存-磁盘-网络),此外,我还加了一个内存复用池,用来复用已经申请好内存空间的bitmap对象的复用,为啥要自己写个Glide呢?因为要定义自己的磁盘缓存规则,场景就是不同的用户保存到不同的磁盘文件中,来完成磁盘图片文件跟用户绑定上传的功能。
三级缓存
private ActiveCache activeCache; // 活动缓存
private MemoryCache memoryCache; // 内存缓存
private DiskLruCacheImpl diskLruCache; // 磁盘缓存
private Set<WeakReference<Value>> reusablePool;//内存复用池
Glide在内存缓存中加了一层设计,就是分为活动缓存和内存缓存。内存缓存采用Lrucache来缓存尚未被GC回收的图片,活动缓存则是缓存正在使用的图片,内存缓存和活动缓存中的图片是互斥的,就是正在使用的图片不会在内存缓存中,在内存缓存中的图片不会在活动缓存,这就是Glide第一级缓存,内存缓存。
Glide缓存二之磁盘缓存,这里采用LruDiskCache,也是github开源的一个项目,这里重点介绍下,因为这里涉及到比较多的设计:
1.前面提到了内存复用池,自然从磁盘加载到内存中时,首先看看内存复用池是否有满足条件的内存区域可以使用:
private boolean isBitmapReusable(Bitmap bitmap,int w,int h,int inSampleSize){
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT){
//版本控制,这里必须要相等才能复用
return bitmap.getWidth() == w && bitmap.getHeight() == h && inSampleSize==1;
}
if (inSampleSize > 1){
w /= inSampleSize;
h /= inSampleSize;
}
int byteCount = getBytesPerPixel(bitmap.getConfig());
//复用的内存池必须大于或者等于从磁盘加载的图片文件的字节数
return byteCount <= bitmap.getAllocationByteCount();
}
缓存三之网络缓存,当内存和磁盘都未命中时,此时就要去加载外部资源,我这里只写了网络的情况,
if (responseCode == HttpURLConnection.HTTP_OK) {
inputStream = httpURLConnection.getInputStream();
byte[] inputStream2ByteArr = inputStream2ByteArr(inputStream);
//TODO 网络上获取图片 模拟接收过程。
BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
//如果直接decodeStream 的话,二次开启的时候返回的bitmap为空,这里转化为字节数组
BitmapFactory.decodeByteArray(inputStream2ByteArr,0,inputStream2ByteArr.length,options);
int w = options.outWidth;
int h = options.outHeight;
options.inSampleSize = caculateInsampleSize(w,h,80,80);
options.inJustDecodeBounds = false;
options.inMutable =true;//设置可变
options.inBitmap = reusable;
final Bitmap bitmap = BitmapFactory.decodeByteArray(inputStream2ByteArr,0,inputStream2ByteArr.length,options);
options.inMutable =true,这个就是为了内存复用做准备,首先要设置图片可变才能复用,加载完成图片后,在调用diskLrucache.put(key,value)方法,这里可以把key缓存下来,这个key就是图片url经过加密后的字符串,在遍历key集合,就可以完成多图的保存了。
关于磁盘缓存地址选择
public static File getDiskCacheDir(Context context, String uniqueName) {
String cachePath;
if (Environment.MEDIA_MOUNTED.equals(Environment.getExternalStorageState())
|| !Environment.isExternalStorageRemovable()) {
cachePath = context.getExternalCacheDir().getPath();
} else {
cachePath = context.getCacheDir().getPath();
}
return new File(cachePath + File.separator + uniqueName);
}
这里做了个判断,是否有SD卡,有SD卡,才能储存到应用私有目录中去。
总结
写的比较简单,有问题的话可以留言,我在详细一些去介绍,网上的三级缓存太多了,这里参照Gilde来写,用法和Glide一样。