Android 缓存(1)---内存缓存LruCache
来源:互联网 发布:万达电商 网络没说过 编辑:程序博客网 时间:2024/05/22 06:30
前言
LruCache中:LRU是指Least Recently Used,即最近最少使用算法,Cache就是是缓存了。
- 缓存其实就是本地的一个备份,读取网络后,先把图片下载到本地,然后从本地加载到容器。这样下一次再加载这张图的时候,就不需要从网络读取了,直接从本地加载。省流量不说,用户体验也会更好。
- Lru策略的目的其实就是如果缓存空间存满了,又需要往里添加,就删掉最近没有用到的。
用法
创建实例:
//当前进程可用容量int maxMemory = (int) Runtime.getRuntime().maxMemory();//缓存空间一般为总量的1/8int cacheSize = maxMemory/8;lruCache = new LruCache<String, Bitmap>(cacheSize){ //获取bitmap大小 @Override protected int sizeOf(String key, Bitmap value) { return value.getByteCount()/1024; } //缓存删除的时候调用 @Override protected void entryRemoved(boolean evicted, String key, Bitmap oldValue, Bitmap newValue) { super.entryRemoved(evicted, key, oldValue, newValue); }};
写入图片缓存
lruCache.put(key,bitmap);
读取图片缓存
lruCache.get(key)
源码
构造函数
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); }
设置最大缓存值
创建LinkedHashMap对象,其中前面两个参数就是HashMap构造函数需要的参数,后面的true表明LinkedHashMap按照访问的次序来排序。
- 按照访问的次序来排序的含义:当调用LinkedHashMap的get(key)或者put(key, value)时,碰巧key在map中被包含,那么LinkedHashMap会将key对象的entry放在线性结构的最后。
- 按照插入顺序来排序的含义:调用get(key), 或者put(key, value)并不会对线性结构产生任何的影响。
这个类是实现Lru算法的关键,有兴趣的可以看看这个类的原理。
get
/** * Returns the value for {@code key} if it exists in the cache or can be * created by {@code #create}. If a value was returned, it is moved to the * head of the queue. This returns null if a value is not cached and cannot * be created. */ public final V get(K key) { if (key == null) { throw new NullPointerException("key == null"); } V mapValue; synchronized (this) { mapValue = map.get(key); if (mapValue != null) { hitCount++; return mapValue; } missCount++; } /* * Attempt to create a value. This may take a long time, and the map * may be different when create() returns. If a conflicting value was * added to the map while create() was working, we leave that value in * the map and release the created value. */ V createdValue = create(key); if (createdValue == null) { return null; } synchronized (this) { createCount++; mapValue = map.put(key, createdValue); if (mapValue != null) { // There was a conflict so undo that last put map.put(key, mapValue); } else { size += safeSizeOf(key, createdValue); } } if (mapValue != null) { entryRemoved(false, key, createdValue, mapValue); return mapValue; } else { trimToSize(maxSize); return createdValue; } }
13-20行中:如果map取出来的值不为null,直接返回。
14行:调用了linkHashMap的get方法。
public V get(Object key) { LinkedHashMapEntry<K,V> e = (LinkedHashMapEntry<K,V>)getEntry(key); if (e == null) return null; e.recordAccess(this); return e.value; }
其中重点为recordAccess
void recordAccess(HashMap<K,V> m) { LinkedHashMap<K,V> lm = (LinkedHashMap<K,V>)m; //如果是访问排序 if (lm.accessOrder) { lm.modCount++; //移除 remove(); //添加到对列尾部 addBefore(lm.header); } }
29行:否则 重新创建
30-32:如果创建的为null,返回null。这个create(key)在我们没有重写的时候默认返回null。
36行:将createdValue插入缓存。
38-40行:如果不为null,则证明之前插入的key有对应的数据,因此撤销插入操作,重新将mapValue插入,替代之前插入的createdValue。发生这种情况的主要原因是在29行的创建操作比较耗时,在创建好之前就已经插入了。
42行:如果mapValue==null,则证明此前key没有对应value,36行的插入是没有问题的。因此需要重新计算大小。
46-48行:调用entryRemoved,返回mapValue
50-51行:重新调整缓存大小,超过限定值则移除不常用的缓存,并返回createdValue。
put
/** * Caches {@code value} for {@code key}. The value is moved to the head of * the queue. * * @return the previous value mapped by {@code key}. */ 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; }
15行:添加前测量缓存大小,safeSizeOf(key, value)实际上调用我们初始化时的sizeOf()方法。
16行:插入缓存。
17-19行:如果已经存在,删除缓存
26行:重新调整缓存大小,超过限定值则移除不常用的缓存
trimToSize
/** * Remove the eldest entries until the total of remaining entries is at or * below the requested size. * * @param maxSize the maximum size of the cache before returning. May be -1 * to evict even 0-sized elements. */ 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); } }
18-20行:如果缓存小于设定的最大值,或为null,直接break。
22-27行:删除第一个缓存
- Android 缓存(1)---内存缓存LruCache
- Android内存缓存LruCache
- Android 内存缓存 LruCache
- Android LruCache(内存缓存)
- Android LruCache(内存缓存)
- android LruCache的使用 (本地缓存+内存缓存)
- Android缓存机制Lrucache内存缓存和DiskLruCache磁盘缓存
- android LruCache内存缓存学习(重写sizeOf方法)
- 内存缓存技术LruCache
- 内存缓存与LruCache
- 内存缓存LruCache算法
- 内存缓存LruCache详解
- 内存缓存和LruCache
- 内存缓存LruCache详解
- android 提供的内存缓存LruCache.java
- android LruCache内存缓存源码解析
- Android LruCache内存缓存实现详解
- Android LruCache内存缓存实现详解
- JAVA中自定义Exception的方法
- 开发人员实用的在线工具
- php中HTTP_X_FORWARDED_FOR 和 REMOTE_ADDR
- 011
- <meta http-equiv="" content="">详解
- Android 缓存(1)---内存缓存LruCache
- Android studio 导入依赖工程
- 车站分级 洛谷p1983
- jQuery中length慢
- unity build webGL失败,Build error with IL2CPP 解决办法
- Oracle数据库概述
- php 爬虫的几种方式
- 关于Oracle存储过程中是否需要写commit的问题
- .Net4.0 任务(Task)