第12章,Bitmap的加载和Cache读书笔记
主要讲解高效的加载Bitmap。还有就是Android中常用的缓存策略,常用LruCache和DiskLruCache。内存缓存和存储缓存。Lru是 least Recently Used的缩写。即是最少使用算法。核心思想为:当缓存快满时,会淘汰近期最少使用的缓存。
Bitmap的高效加载
BitmapFactory类提供四类方法:
- decodeFile
- decodeResource
- decodeStream
- decodeByteArray
分别从文件系统、资源、输入流以及字节数组中加载一个Bitmap对象,其中decodeFile和decodeResource又间接的调用了decodeStream方法。这四类方法最终是在底层实现,对应BitmapFactory类的几个native方法。
可以通过BitmapFactory.Options来缩放图片。从而减少内存的占用。主要通过inSampleSize参数。即采样率。当inSampleSiez为1的时候时,采样后的图片大小为图片的原始大小;若为2的时候,那么采样后的图片宽高均为原图的1/2,而像素为原图的1/4,其占有的内存也为原图的1/4。如 1024 1024 4:4MB。如果inSampleSize为2,512 512 4 : 1MB。采样率必须大于1才有效果。并且采样率同时作用于宽高,这导致缩放后的图片大小以采样率的2次方递减。
如何获取采样率:
- 将BitmapFactory.Options的inJustDecodeBounds参数设置为true并加载图片
- 从BitmapFactory.Options中取出图片的原始宽高信息,他们对应于ontWidth和outHeight参数。
- 根据采样率的规则并且结合目标的View的所需大小计算出采样率inSampleSize。
- 将BitmapFactory.Options的inJustDecodeBounds参数设置为false,然后重新加载图片。
inJustDecodeBounds参数设置为true,BitmapFactory只会解析图片的原始宽高而不会真正的加载图片。所以这个操作是轻量级的。
Android中的缓存策略
常用的的一种缓存算法LRU(Least Recently Used),LRU是近期最少使用算法。采用LRU算法的缓存有两种:LruCache和DiskLruCache,LruCache用于实现内存缓存,而DiskLruCache是磁盘缓存。
LruCache
LruCache是一个泛型类,它内部采用一个LinkedHashMap以强引用的方式储蓄外界的缓存对象,其提供了get和put方法来完成缓存的获取和添加操作。
- 强引用:直接的对象引用
- 软引用:当一个对象只有软引用存在时,系统内存不足时此对象会被gc回收
- 弱引用:当一个对象只有弱引用时。此对象随时gc回收
典型的初始化过程:
int maxMemory = (int) (Runtime.getRuntime().maxMemory() / 1024);
int cacheSize = maxMemory / 8;
mMemoryCache = new LruCache<String, Bitmap>(cacheSize) {
@Override
protected int sizeOf(String key, Bitmap value) {
return value.getRowBytes() * value.getHeight() / 1024;
}
};
获取和添加
mMemoryCache.get(key)
mMemoryCache.put(key,bitmap)
也支持删除操作,通过remove方法即可删除一个指定的缓存对象。
DiskLruCache
DiskLruCache不能通过构造函数来创建,它提供了open方法来创建本身。
public static DiskLruCache open(File directory, int appVersion, int valueCount, long maxSize)
- File directory 代表磁盘缓存存在文件的文件系统中的存储路径。如Sd卡的缓存目录。
- int appVersion 代表着版本号,版本改变之前的缓存都会被清除。一般设为1即可。因为版本改变,多数情况缓存文件还是有效的。
- int valueCount 代表着单个节点所对应的数据个数,一般设为1即可。
- long maxSize 代表缓存总大小,例如50MB
DiskLruCache缓存的添加
DiskLruCache缓存的添加的操作是通过Editor完成的。Editor代表一个缓存对象的编辑对象。
可以通过edit来获取Editor对象
private synchronized Editor edit(String key, long expectedSequenceNumber)
如果这个缓存正在被编辑,那么edit会返回Null,通过Key获取Editor对象。并且通过它可以得到一个文件输入流。
由于前面的DiskLruCache的open方法中设置了一个节点只有一个数据。所以DISK_CACHE_INDEX常量设置为0即可。
OutputStream outputStream = editor.newInputStream(DISK_CACHE_INDEX);
拿到输出流后就可以通过这个文件输出流写入文件系统上。而且还必须通过Editor的commit()来提交写入操作。如果发送异常还可以通过Editor的abort()来回退整个操作。
DiskLruCache的缓存查找
和添加类是。也是通过Key获取snapShot对象。通过它获取缓存的输入流。
此外,DiskLruCache还提供remove、delete方法。
ImageLoader的实现
优秀的ImageLoader应该具备如下条件
- 图片的同步加载
- 图片的异步加载
- 图片压缩
- 内存缓存
- 磁盘缓存
- 网络拉取
具体实现看Demo代码。