android lru緩存 輔助類LruCache 使用和解析
LruCache 緩存到底是什麼,LRU是Least Recently Used 的縮寫,翻譯過來就是“最近最少使用”,LRU緩存就是使用這種原理實現,簡單的說就是緩存一定量的數據,當超過設定的閾值時就把一些過期的數據刪除掉,比如我們緩存100M的數據,當總數據小於100M時可以隨意添加,當超過100M時就需要把新的數據添加進來,同時要把過期數據刪除,以確保我們最大緩存100M。 聽瞭lrucache的作用,是不是很適合作為一種內存管理的方法呢
構造方法
/** * @param maxSize for caches that do not override {@link #sizeOf}, this is * the maximum number of entries in the cache. For all other caches, * this is the maximum sum of the sizes of the entries in this cache. */ public LruCache(int maxSize) { if (maxSize <= 0) { throw new IllegalArgumentException("maxSize <= 0"); } this.maxSize = maxSize; this.map = new LinkedHashMap(0, 0.75f, true); }
可以看到構造方法中設置瞭最大的size同時創建瞭一個LinkedHashMap。
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); //如果已經存在返回v if (previous != null) { //如果已經存在減掉已經加上的長度 size -= safeSizeOf(key, previous); } } if (previous != null) { // 方法通知舊數據被更新為新的值 entryRemoved(false, key, previous, value); } trimToSize(maxSize); return previous; }
get方法
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; } }
可以看到get方法傳入瞭key進行查找,如果找到就返回,同時默認返回空的creat方法,當creat被重寫後,creat可能會耗時,同時createdValue可能會改變,同時可能會有put方法將新的同樣的key的方法添加進去,所以後面會看到和put方法一樣的操作。
trimToSize方法
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 toEvict = map.entrySet().iterator().next(); key = toEvict.getKey(); value = toEvict.getValue(); map.remove(key); size -= safeSizeOf(key, value); evictionCount++; } entryRemoved(true, key, value, null); } }
同時trimToSize方法將會對溢出情況進行判斷,移除最少使用的部分。