使用強引用來快取有限數量的值.每次被訪問的值,將會移動到佇列的頭部。當佇列大小超過快取大小時,佇列尾部的值將會被刪除並且允許垃圾回收器將它回收。
如果你需要明確知道快取資料什麼時候被釋放,需要重寫 entryRemoved();方法
如果出現快取缺失時,可以重寫create();方法。使用這種簡單的方法,可以確保永遠存在返回值。
預設的,快取大小是根據快取項數量來計算的。可以重寫sizeOf()方法來設定不同的計算快取大小的單位。例如用於快取4MiB的圖片:
int cacheSize = 4 * 1024 * 1024;//用於計算快取總Size
LruCache<String, Bitmap> bitmapCache = new LruCache<String, Bitmap>(cacheSize){
protected int sizeOf(String key, Bitmap value){
return value.getByteCount();//返回每一張圖片Size
}
}
複製程式碼
這個類是執行緒安全的,多個快取的原子操作程式碼:
syschronized(cache){
if(cache.get(key) == null){
cache.put(key, value);
}
}
複製程式碼
這個類不允許
null
作為key或者value。如果get()
,put()
和remove()
方法中返回值為null
,那麼就明確表明,快取中不存在這個值。
這個類在Anroid3.1加入,如果需要在之前版本中使用,請使用support包中程式。
成員變數
private final LinkedHashMap<K, V> map;//Cache 快取的主要是實現基礎。
private int size;//基於某個單位上的快取大小,不一定等於快取成員數量。具體數量和size的轉換,通過方法sizeOf()實現。
private int maxSize;//初始化時傳入的,快取最大值。
private int putCount;//put()方法呼叫次數。
private int createCount;//create()方法呼叫次數。
private int evictionCount;//超出限制,被刪除的數量。
private int hitCount;//返回get()方法正常獲取快取資料次數。
private int missCount;//返回get()方法為在快取中獲取資料的次數。
複製程式碼
構造方法
public LruCache(int maxSize) {
this.maxSize = maxSize;
this.map = new LinkedHashMap<K, V>(0, 0.75f, true);
}
複製程式碼
在建構函式中,初始化了成員變數中的LinkedHashMap()。LRUCache主要實現感覺更多的是LinkedHashMap的學習。 LinkedHashMap是HashMap增加一個雙向連結串列。 所以LinkedHashMap可以插入順序或者訪問順序訪問。 LinkedHashMap構造引數中最後一個引數accessOrder,用來判斷是使用哪種順序。accressOrder等於true為訪問順序, 等於false 為資料插入順序。
LinkedHashMap重寫了HashMap的Entry。增加了before和after,使Entry雖然存在HashMap中但是另外也存在一個雙向連結串列。因此LinkedHashMap可以方便的通過訪問和插入順序來訪問某個Entry。也正是因為LinkedHashMap存在這個訪問資料順序序,所以用它來做LRUCache,方便刪除最早之前加入的資料,並且可以根據訪問順序來調整連結串列順序。
關於LinkedHashMap推薦部落格:http://blog.csdn.net/justloveyou_/article/details/71713781
get()方法
public final V get(K key) {
V mapValue;
synchronized (this) {
//從map中查詢資料
mapValue = map.get(key);
if (mapValue != null) {
//存在則直接返回。並且查詢成功計數變數hitCount++
hitCount++;
return mapValue;
}
//查詢失敗計數變數missCount++
missCount++;
}
/*
* 下面嘗試使用 create()方法建立一個新值,加到到map中。而且如果新值存在衝突,將會保留以前的值。
* create()方法預設返回值為null。
*/
V createdValue = create(key);
if (createdValue == null) {
return null;
}
synchronized (this) {
createCount++;
//將建立的值新增到map中,並返回key以前對應的value。
mapValue = map.put(key, createdValue);
//key以前存在對應值,則將以前的值重新新增到map中,捨棄新建立值。
//否則將size增加新建value 所佔size。
if (mapValue != null) {
map.put(key, mapValue);
} else {
size += safeSizeOf(key, createdValue);
}
}
//mapValue不為null,使用mapValue替換了createValue,呼叫entryRemoved()。
//為null,則重新計算是否越界。
if (mapValue != null) {
entryRemoved(false, key, createdValue, mapValue);
return mapValue;
} else {
trimToSize(maxSize);
return createdValue;
}
}
複製程式碼
put方法
/**
* 將鍵值對插入到佇列頭部。
* @return 返回以前與這個key相對應的Value。
*/
public final V put(K key, V value) {
V previous;
synchronized (this) {
putCount++;
size += safeSizeOf(key, value); //當前總size加上新加入Entry的size
previous = map.put(key, value); //加入Map中
//如果以前與key相對應value不為空,那麼size減去那個value佔據size。
if (previous != null) {
size -= safeSizeOf(key, previous);
}
}
//因為刪除了previous 所以呼叫entryRemoved()方法。
if (previous != null) {
entryRemoved(false, key, previous, value);
}
trimToSize(maxSize);
return previous;
}
複製程式碼
remove()方法
/**
* 移除被 key對應的entry,如果不存在返回null。
*/
public final V remove(K key) {
V previous;
synchronized (this) {
previous = map.remove(key);
if (previous != null) {
size -= safeSizeOf(key, previous);
}
}
if (previous != null) {
entryRemoved(false, key, previous, null);
}
return previous;
}
複製程式碼
resize()方法和trimToSize()方法和evictAll()
/**
* 設定快取size
*/
public void resize(int maxSize) {
if (maxSize <= 0) {
throw new IllegalArgumentException("maxSize <= 0");
}
synchronized (this) {
this.maxSize = maxSize;
}
trimToSize(maxSize);
}
/**
* 刪除超出MaxSize的最早加入的entry。
*/
public void trimToSize(int maxSize) {
while (true) {
K key;
V value;
synchronized (this) {
if (size <= maxSize) {
break;
}
//返回map中最古老的entry,如果map為空則返回null。
Map.Entry<K, V> toEvict = map.eldest();
if (toEvict == null) {
break;
}
key = toEvict.getKey();
value = toEvict.getValue();
//從map中移除最古老的entry
map.remove(key);
//size進行相應的減少
size -= safeSizeOf(key, value);
//修改被移除次數
evictionCount++;
}
//因為最古老的entry的唄刪除了,所以呼叫entryRemoved().
entryRemoved(true, key, value, null);
}
}
/**
* 清空快取
*/
public final void evictAll() {
trimToSize(-1); // -1 will evict 0-sized elements
}
複製程式碼
部分protected 方法
/**
* 返回entry中每個value對應的在總size中佔據的大小。上面說明中通過重寫該方法,
* 實現一個用於快取Bitmap的LruCache
*/
protected int sizeOf(K key, V value) {
return 1;
}
/**
*當entry被remove或者被put方法替換或者被刪除最古老值時 呼叫此方法
*evicted 為true為刪除掉最古老值時呼叫 ;false為remove()或者put()方法中呼叫。
*/
protected void entryRemoved(boolean evicted, K key, V oldValue, V newValue) {}
/**
*當呼叫get方法,沒有與key相對的值時調動。
*/
protected V create(K key) {
return null;
}
複製程式碼