我们都知道安卓系统对内存的消耗的条件是相当苛刻的,一般安卓系统规定每个APP占用的内存不能超过整个系统RunningMemory的1/8之一不然系统会OOM并杀死程序,那么对于每个APP在使用内存时就要谨慎再谨慎。这篇文章主要讲的就缓存工具类-----LruCache。
一.LruCache详解
LruCache 是 Android 的一个内部类,提供了基于内存实现的缓存
LRU 的工作原理,最近使用的会放进队列的头部,最久未使用的放进队列的尾部,会首先删除队尾元素
- 如果你 cache 的某个值需要明确释放,重写 entryRemoved 方法
- 如果 key 相对应的 item 丢掉,重写create(),这简化了调用代码,即使丢失了也总会返回。
- 默认的,我们需要重写 sizeOf 方法
- 该类是线程安全的
- 该类不允许空值和空 key
二.LruCache的变量和方法解释
private int size;// 当前大小 private int maxSize;// 最大容量 private int putCount;// put次数 private int createCount;// 创建次数 private int evictionCount;// 回收次数 private int hitCount;// 命中次数 private int missCount;// 未命中次数
resize()
重新计算缓存的大小,里面涉及到了 trimToSize 方法。
trimToSize()
该方法根据 maxSize 来调整内存 cache 的大小,如果 maxSize 传入 -1,则清空缓存中的所有对象。该源码可知,该内部是一个死循环,靠满足相应的条件达到退出的目的
- 条件1,当当前大小 size 小于 最大容量时,退出
- 当需要删除的 entry 为空时,会退出
safeSizeOf()
里面涉及到了我们需要复写的方法 sizeOf
entryRemoved()
当 item 被回收或者删掉时调用。该方法当 value 被回收释放存储空间时被 remove 调用,或者替换 item 值时 put 调用,
默认实现什么都没做。每次回收对象就调用该函数,这里参数为 true --为释放空间被删除;false --get、put 或 remove 导致,需要用户考量进行重写。
get()
通过 key 返回相应的 item,或者创建返回相应的 item。相应的 item 会移动到队列的头部,如果 item 的 value 没有被 cache 或者不能被创建,则返回 null。
create()
create 函数是根据 key 来创建相应的 item,但是在 LruCache 中默认返回的是null。因为 LruCache 未记录被回收的数据,这里读者可以重写该 create 函数,为 key 创建相应的 item,这里是需要读者自行设计。请注意,多线程会导致冲突。
put()
put(K key, V value)
remove()
remove(K key)
总结
- LruCache 封装了 LinkedHashMap,提供了 LRU 缓存的功能;
- LruCache 通过 trimToSize 方法自动删除最近最少访问的键值对;
- LruCache 不允许空键值;
- LruCache 线程安全;
- LruCache 的源码在不同版本中不一样,需要区分
- 继承 LruCache 时,必须要复写 sizeOf 方法,用于计算每个条目的大小。
三.DEMO
ps:里面有些方法在上篇文章安卓AsyncTask详解有写,这里就不写了。
private LruCache<ImageView, Bitmap> lruCache;
public LruCacheView() {
int maxMemory = (int) Runtime.getRuntime().maxMemory();
int cacheSize = maxMemory / 4;
Logs.e("系统占用内存大小: " + cacheSize);
// 创建LruCache对象,同时用匿名内部类的方式重写方法
lruCache = new LruCache<ImageView, Bitmap>(cacheSize) {
@Override
protected int sizeOf(ImageView key, Bitmap value) {
//return super.sizeOf(key, value);
// 在每次存入缓存的时候调用,我们需要直接返回Bitmap value的实际大小
return value.getByteCount();
}
};
}
/*存储数据到LruCache*/
private void addToCache(ImageView img, Bitmap bitmap) {
if (getFromCache(img) == null) {
lruCache.put(img, bitmap);
}
}
/*从LruCache得到数据*/
private Bitmap getFromCache(ImageView img) {
return lruCache.get(img);
}