Android LruCacheの原理
Android LruCacheの原理
LruCacheは、Least Recently Used(最近最小使用)アルゴリズムに基づいて実現されるスレッドセキュリティのデータキャッシュクラスであり、設定されたキャッシュ容量を超えた場合、最近最小使用されているデータLruCacheを優先的に淘汰するLRUキャッシュポリシーはLinkedHashMapによって実現され、get/putなどの関連メソッドをカプセル化することによって制御キャッシュサイズおよび淘汰要素が実現されるが、nullのkeyおよびvalueはサポートされない
だからLinkedHashMapの原理を勉強してこそ,本論文の理解に役立つ.
使用方法
LruCacheを作成する前にキャッシュサイズを定義し、コンストラクション関数にキャッシュサイズを入力し、sizeOfメソッドを書き換えてvalueのサイズを計算します.LruCacheキャッシュBitmapの一般的な使用方法は次のとおりです.
初期化
LruCacheにはコンストラクション関数が1つしかありません.入力されたパラメータはLruCacheのキャッシュサイズです.その後、操作順序に基づいてソートされたLinkedHashMapを作成します.
デフォルトsizeOf関数は1を返し、各valueサイズが1であることを示します.
Bitmapをキャッシュするなどの特別な要件がある場合はsizeOfメソッドを書き換え、bitmapが消費するメモリサイズを返す必要があります.
put
putメソッドはまず空判定処理を行うため,空のキー値ペアを保存することができず,ロックによりスレッドセキュリティを実現し,putデータのたびに容量を計算する.
trimToSizeメソッドでは、最も一般的ではないデータを最大容量を超えないまで繰り返し削除し、最も一般的ではないデータはデュアルチェーンテーブルのトップにあります.
get
getメソッドも同様にまずkeyを空にしてkeyでvalueを取得し、createメソッドを書き換えるとそのメソッドで作成したvalueが保存されますが、この場合他のスレッドがputメソッドを呼び出して先にvalueを挿入する可能性があるため、撤回処理を行います
remove
removeメソッドは簡単です.LinkedHashMapのremoveメソッドを呼び出し、メモリサイズを計算します.
LruCacheは、Least Recently Used(最近最小使用)アルゴリズムに基づいて実現されるスレッドセキュリティのデータキャッシュクラスであり、設定されたキャッシュ容量を超えた場合、最近最小使用されているデータLruCacheを優先的に淘汰するLRUキャッシュポリシーはLinkedHashMapによって実現され、get/putなどの関連メソッドをカプセル化することによって制御キャッシュサイズおよび淘汰要素が実現されるが、nullのkeyおよびvalueはサポートされない
だからLinkedHashMapの原理を勉強してこそ,本論文の理解に役立つ.
使用方法
LruCacheを作成する前にキャッシュサイズを定義し、コンストラクション関数にキャッシュサイズを入力し、sizeOfメソッドを書き換えてvalueのサイズを計算します.LruCacheキャッシュBitmapの一般的な使用方法は次のとおりです.
private LruCache<String, Bitmap> mMemoryCache;
@Override
protected void onCreate(Bundle savedInstanceState) {
// , OutOfMemory
int maxMemory = (int) (Runtime.getRuntime().maxMemory() / 1024);
// 1/8 , KB
int cacheSize = maxMemory / 8;
// LruCache
mMemoryCache = new LruCache<String, Bitmap>(cacheSize) {
@Override
protected int sizeOf(String key, Bitmap bitmap) {
// sizeOf
return bitmap.getAllocationByteCount() / 1024;
}
};
}
public void addBitmapToCache(String key, Bitmap bitmap) {
mMemoryCache.put(key, bitmap);
}
public Bitmap getBitmapFromCache(String key) {
return mMemoryCache.get(key);
}
初期化
LruCacheにはコンストラクション関数が1つしかありません.入力されたパラメータはLruCacheのキャッシュサイズです.その後、操作順序に基づいてソートされたLinkedHashMapを作成します.
public LruCache(int maxSize) {
if (maxSize <= 0) {
throw new IllegalArgumentException("maxSize <= 0");
}
//
this.maxSize = maxSize;
// LinkedHashMap accessOrder true
this.map = new LinkedHashMap<K, V>(0, 0.75f, true);
}
デフォルトsizeOf関数は1を返し、各valueサイズが1であることを示します.
protected int sizeOf(K key, V value) {
return 1;
}
Bitmapをキャッシュするなどの特別な要件がある場合はsizeOfメソッドを書き換え、bitmapが消費するメモリサイズを返す必要があります.
mMemoryCache = new LruCache<String, Bitmap>(cacheSize) {
@Override
protected int sizeOf(String key, Bitmap bitmap) {
// sizeOf
return bitmap.getAllocationByteCount() / 1024;
}
};
put
putメソッドはまず空判定処理を行うため,空のキー値ペアを保存することができず,ロックによりスレッドセキュリティを実現し,putデータのたびに容量を計算する.
public final V put(K key, V value) {
// null key value
if (key == null || value == null) {
throw new NullPointerException("key == null || value == null");
}
V previous;
//
synchronized (this) {
putCount++;
//
size += safeSizeOf(key, value);
// , , null
previous = map.put(key, value);
if (previous != null) {
//
size -= safeSizeOf(key, previous);
}
}
if (previous != null) {
// ,
entryRemoved(false, key, previous, value);
}
//
trimToSize(maxSize);
return previous;
}
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<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);
}
}
get
getメソッドも同様にまずkeyを空にしてkeyでvalueを取得し、createメソッドを書き換えるとそのメソッドで作成したvalueが保存されますが、この場合他のスレッドがputメソッドを呼び出して先にvalueを挿入する可能性があるため、撤回処理を行います
public final V get(@NonNull K key) {
// key
if (key == null) {
throw new NullPointerException("key == null");
}
V mapValue;
synchronized (this) {
// key value
mapValue = map.get(key);
if (mapValue != null) {
hitCount++;
// value
return mapValue;
}
missCount++;
}
// create , null,
V createdValue = create(key);
if (createdValue == null) {
return null;
}
synchronized (this) {
createCount++;
// create value
mapValue = map.put(key, createdValue);
// value
if (mapValue != null) {
// There was a conflict so undo that last put
// value, value create value
map.put(key, mapValue);
} else {
// value,
size += safeSizeOf(key, createdValue);
}
}
if (mapValue != null) {
entryRemoved(false, key, createdValue, mapValue);
return mapValue;
} else {
trimToSize(maxSize);
return createdValue;
}
}
remove
removeメソッドは簡単です.LinkedHashMapのremoveメソッドを呼び出し、メモリサイズを計算します.
public final V remove(@NonNull 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) {
entryRemoved(false, key, previous, null);
}
return previous;
}