編輯:關於Android編程
LRU(Least Recently Used)最近最少使用算法
緩存保存了一個強引用(Android 2.3開始,垃圾回收器更傾向於回收弱引用和軟引用,軟引用和弱引用變得不可靠,Android 3.0中,圖片的數據會存儲在本地的內存當中,因而無法用一種可預見的方式將其釋放)限制值的數量. 每當值被訪問的時候,它會被移動到隊列的頭部. 當緩存已滿的時候加入新的值時,隊列中最後的值會出隊,可能被回收LRUCache內部維護主要是通過LinkedHashMap實現
這是一個安全的線程,多線程緩存通過同步實現?
默認情況下,緩存的大小是由值的數量決定,重寫sizeOf計算不同的值
如果你緩存值需要明確釋放,重寫entryRemoved()
int maxMemory = (int) Runtime.getRuntime().maxMemory();
int mCacheSize = maxMemory / 8;
//給LruCache分配1/8 4M
mMemoryCache = new LruCache(mCacheSize){
//必須重寫此方法,來測量Bitmap的大小
@Override
protected int sizeOf(String key, Bitmap value) {
return value.getRowBytes() * value.getHeight();
}
};
mMemoryCache.put(key, bitmap)
mMemoryCache.get(key)
這個類不允許有空的鍵值. get,put,remove 返回空值,key對應的值不在緩存中
構造函數,初始化了最大容量和LinkedHashMap
/**
* @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);
}
這裡將LinkedHashMap最後一個參數(accessOrder)設置為true,將accessOrder設置為true時,可以使遍歷順序和訪問順序一致,其內部雙向鏈表將會按照近期最少訪問到近期最多訪問的順序排列Entry對象
put方法,首先不允許鍵值為空,然後是線程安全,put的次數加一,size增加,以鍵值對的形式存入LinkedHashMap,如果之前已經存在了這個鍵值對,size減少成原來的大小,如果容量超過maxsize,將會刪除最近很少訪問的entry
/**
* 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;
}
put方法有一個很關鍵的地方超過最大值是會刪除最近最少訪問的
trimToSize首先線程安全,檢查當前大小是否大於最大值,如果大於最大值,從LinkedHashMap中去除最近最少(循環刪除鏈表首部元素)被訪問的元素,獲得鍵值,刪除
/**
* 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) {
break;
}
Map.Entry toEvict = map.eldest();
if (toEvict == null) {
break;
}
key = toEvict.getKey();
value = toEvict.getValue();
map.remove(key);
size -= safeSizeOf(key, value);
evictionCount++;
}
entryRemoved(true, key, value, null);
}
}
get方法,首先key不能為空,線程安全,根據key,從LinkedHashMap中獲得value,不為空的話返回,為空的話,創建一個key,創建失敗返回null,創建成功,在LinkedHashMap中創建鍵值對,存在就覆蓋,不存在size增加,返回value值
/**
* 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;
}
}
核心代碼分析完畢,想知道LinkedHashMap,請聽下回哔哔
Android自定義SurfaceView與傳感器的並用(實現自繪的指北針)
概述:SurfaceView是Android中極為重要的繪圖容器,SurfaceView的圖像繪制是放在主線程之外的另一個線程中完成的。除了繪圖,SurfaceView還
Android中的廣播(BroadCast)詳細介紹
什麼是廣播在Android中,Broadcast是一種廣泛運用的在應用程序之間傳輸信息的機制。我們拿廣播電台來做個比方。我們平常使用收音機收音是這樣的:許許多多不同的廣播
探究drawable圖片的加載原理和縮放規律
前言Android的源碼公開策略豐富了手持設備的多樣性,但隨之而來的卻是較為嚴重的”碎片化”——版本繁多、尺寸多樣、功能定
手機百度視頻添加收藏教程
百度視頻播放器是百度公司推出的一款為Android用戶精心優化的免費視頻應用,集視頻搜索、視頻推薦、離線觀看、劇集提醒等等眾多創新優秀功能於一身。它不僅僅是