public LruCache(int maxSize) {
// maxsize不允許<0 建議使用Runtime.getRuntime().maxMemory() / 8
if (maxSize <= 0) {
throw new IllegalArgumentException("maxSize <= 0");
}
this.maxSize = maxSize;
// 初始化LinkedHashMap
this.map = new LinkedHashMap<K, V>(0, 0.75f, true);
}
初始化示例
public class ImageLoader {
private LruCache<String, Bitmap> lruCache;
public ImageLoader() {
int maxMemory = (int)(Runtime.getRuntime().maxMemory() / 1024);
int cacheSize = maxMemory / 8;
lruCache = new LruCache<String, Bitmap>(cacheSize) {
// 初始化LruCache的時候要重寫sizeOf方法,告訴Cache添加的元素大小
// 如果超出最大值就進行刪除操作。
@Override
protected int sizeOf(String key, Bitmap bitmap) {
return bitmap.getRowBytes();
}
};
}
public void addBitmap(String key, Bitmap bitmap) {
if (getBitmap(key) == null) {
lruCache.put(key, bitmap);
}
}
public Bitmap getBitmap(String key) {
return lruCache.get(key);
}
}
2. 增
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() 詳見2.1
size += safeSizeOf(key, value);
// 執行LinkedHashMap的put操作,如果是覆蓋操作會把oldValue返回回來 , 詳見2.2
previous = map.put(key, value);
// 如果oldValue != null size減去oldValue的大小
if (previous != null) {
size -= safeSizeOf(key, previous);
}
}
if (previous != null) {
// 如果oldValue != null , 調用entryRemoved,通知調用者對要刪除的內容進行處理
// 如果不處理忽略即可,LruCache中entryRemoved()是個空方法
// 詳見 2.3
entryRemoved(false, key, previous, value);
}
// 處理size,如果超過maxsize做刪除處理 , 詳見2.4
trimToSize(maxSize);
return previous;
}
2.1 safeSizeOf()
private int safeSizeOf(K key, V value) {
// 在初始化的時候重寫sizeOf,並傳回value的大小
int result = sizeOf(key, value);
if (result < 0) {
throw new IllegalStateException("Negative size: " + key + "=" + value);
}
return result;
}
2.2 map.put()
@Override public V put(K key, V value) {
if (key == null) {
return putValueForNullKey(value);
}
int hash = Collections.secondaryHash(key);
HashMapEntry<K, V>[] tab = table;
int index = hash & (tab.length - 1);
// 遍歷是否有相同的key的Entry , 有就覆蓋,並返回oldValue
for (HashMapEntry<K, V> e = tab[index]; e != null; e = e.next) {
if (e.hash == hash && key.equals(e.key)) {
preModify(e);
V oldValue = e.value;
e.value = value;
return oldValue;
}
}
// No entry for (non-null) key is present; create one
modCount++;
// 是否需要擴容,詳見HashMap擴容源碼分析
if (size++ > threshold) {
tab = doubleCapacity();
index = hash & (tab.length - 1);
}
// 添加新的Entry , 詳見2.2.1
addNewEntry(key, value, hash, index);
return null;
}
2.2.1 addNewEntry(key, value, hash, index);
void addNewEntry(K key, V value, int hash, int index) {
// 初始化HashMapEntry操作,詳見2.2.2
table[index] = new HashMapEntry<K, V>(key, value, hash, table[index]);
}
2.2.2 new HashMapEntry
static class HashMapEntry<K, V> implements Entry<K, V> {
final K key;
V value;
final int hash;
HashMapEntry<K, V> next;
// 把當前Entry設置爲頭部,next指向table[index]下的首個Entry
HashMapEntry(K key, V value, int hash, HashMapEntry<K, V> next) {
this.key = key;
this.value = value;
this.hash = hash;
this.next = next;
}
...
}
2.3 entryRemoved(false, key, previous, value)
// evicted true:在超過maxsize清理空間時被刪除的,false:在put或者removed的時候被刪除的
protected void entryRemoved(boolean evicted, K key, V oldValue, V newValue) {}
2.4 trimToSize(maxsize)
private 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!");
}
// 當前size < 最大size 不作處理
if (size <= maxSize) {
break;
}
// BEGIN LAYOUTLIB CHANGE
// get the last item in the linked list.
// This is not efficient, the goal here is to minimize the changes
// compared to the platform version.
Map.Entry<K, V> toEvict = null;
// 遍歷到最後一個entry
for (Map.Entry<K, V> entry : map.entrySet()) {
toEvict = entry;
}
// END LAYOUTLIB CHANGE
if (toEvict == null) {
break;
}
key = toEvict.getKey();
value = toEvict.getValue();
// 刪除最後一個
map.remove(key);
size -= safeSizeOf(key, value);
evictionCount++;
}
// 控制存儲空間刪除的Entry,所以參數爲true
entryRemoved(true, key, value, null);
}
}
3. 刪
// 刪除流程類似於trimToSize中remove過程
public final V remove(K key) {
if (key == null) {
throw new NullPointerException("key == null");
}
V previous;
synchronized (this) {
previous = map.remove(key);
if (previous != null) {
size -= safeSizeOf(key, previous);
}
}
if (previous != null) {
// 通過remove的Entry,第一參數爲false
entryRemoved(false, key, previous, null);
}
return previous;
}
4. 查
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++;
}
// 如果沒有緩存,如果用戶在初始化Lrucache重寫了create(key),方法並返回內容,擇把用戶返回內容put緩存起來
V createdValue = create(key);
// 如果沒有重寫create,或者重寫返回null,結束
if (createdValue == null) {
return null;
}
synchronized (this) {
createCount++;
// 把create()中生成的Value緩存起來,並返回該位置的oldValue
mapValue = map.put(key, createdValue);
// 如果有該緩存,就撤銷這次put過程,把原來的mapValue重新put進去
if (mapValue != null) {
// There was a conflict so undo that last put
map.put(key, mapValue);
} else {
// 如果原有位置是空的,那麼進行size++操作
size += safeSizeOf(key, createdValue);
}
}
if (mapValue != null) {
// 如果原有位置不是空 , 把原有內容返回
entryRemoved(false, key, createdValue, mapValue);
return mapValue;
} else {
// 如果原有位置是空,重新計算大小
trimToSize(maxSize);
return createdValue;
}
}