android 缓存机制之 LruCache

LruCache将数据缓存在内存中,虽然app的内存有限但是缓存一些必要的小一些的资源还是很有必要的,新建如下cache。

	LruCache<String, Bitmap> mMemoryCache = new LruCache<String, Bitmap>(cacheSize) {
            @Override
            protected int sizeOf(String key, Bitmap bitmap) {
                return bitmap.getRowBytes() * bitmap.getHeight() / 1024;
            }
        };

需要定义

1缓存资源的个数cacheSize

2要怎么计算缓存资源的大小,sizeOf

使用也很简单,跟HashMap似得。

 mMemoryCache.put(key, bitmap);
mMemoryCache.get(key);
使用put放入缓存,使用get获取缓存。

看一下源码:

1)构造函数

public LruCache(int maxSize) {
        if (maxSize <= 0) {
            throw new IllegalArgumentException("maxSize <= 0");
        }
        this.maxSize = maxSize;
        this.map = new LinkedHashMap<K, V>(0, 0.75f, true);
    }

maxSize最大缓存空间,单位和重写的SizeOf中使用的一致就可以了,比如都用byte。

新建了一个LinkedHashMap,这里有三个参数,

第一个HashMap初始大小,

第二个防hash冲突因子,简单说就是在HaspMap中的table数组最多只能利用3/4的空间,因为这个数组的index是利用hash值来计算的,为了减少冲突,只使用其中3/4的空间,超过之后,直接将数组容量翻倍。(这个参数并不影响理解LruCache)

第三个表示是否按照使用的先后顺序排序。(这里会影响,长时间不用的对象就会排到后面,当空间不够的时候,就要释放它了,因此这里传入true)

2)put

public final V put(K key, V value) {
        if (key == null || value == null) {
            throw new NullPointerException("key == null || value == null");
        }

        V previous;
        synchronized (this) {
            putCount++;
            size += safeSizeOf(key, value);
            previous = map.put(key, value);
            if (previous != null) {
                size -= safeSizeOf(key, previous);
            }
        }

        if (previous != null) {
            entryRemoved(false, key, previous, value);
        }

        trimToSize(maxSize);
        return previous;
    }

简答来说就是将对象存进LinkedHashMap, safeSizeOf这里会回调重写的SizeOf方法来获取当期对象的大小,size增加, 如果当前键值已经存在就被替换掉了,size减小。

trimToSize这里会根据size和maxSize大小的比较,来看是否超出最大缓存范围,超出就移除最早用过的那个缓存,直到小于maxsize。代码如下


public void trimToSize(int maxSize) {
        while (true) {
            K key;
            V value;
            synchronized (this) {
                if (size < 0 || (map.isEmpty() && size != 0)) {
                    throw new IllegalStateException(getClass().getName()
                            + ".sizeOf() is reporting inconsistent results!");
                }

                if (size <= maxSize || map.isEmpty()) {
                    break;
                }

                Map.Entry<K, V> toEvict = map.entrySet().iterator().next();
                key = toEvict.getKey();
                value = toEvict.getValue();
                map.remove(key);
                size -= safeSizeOf(key, value);
                evictionCount++;
            }

            entryRemoved(true, key, value, null);
        }
    }


这样就实现了利用linkedHashMap缓存数据。

LinkedHashMap是如何控制移除对象优先级,代码如下在LinkedHas和Map中

void recordAccess(HashMap<K,V> m) {
            LinkedHashMap<K,V> lm = (LinkedHashMap<K,V>)m;
            if (lm.accessOrder) {
                lm.modCount++;
                remove();
                addBefore(lm.header);
            }
        }

每一次使用get()的时候,就会将当前对象移动到链表的头部(heaser)前面,因为LinkedHashMap的数据结构是个环形的双向链表,因此,在header后面的第一个就是最早用过的那个对象,也就是最不常用,在最后空间不足时,从heder后面第一个依次向后取,然后移除释放空间就可以了。





  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值