package
android.util; import
java.util.LinkedHashMap; import
java.util.Map; /** *
A cache that holds strong references to a limited number of values. Each time *
a value is accessed, it is moved to the head of a queue. When a value is *
added to a full cache, the value at the end of that queue is evicted and may *
become eligible for garbage collection. *
Cache保存一个强引用来限制内容数量,每当Item被访问的时候,此Item就会移动到队列的头部。 *
当cache已满的时候加入新的item时,在队列尾部的item会被回收。 *
<p>If your cached values hold resources that need to be explicitly released, *
override {@link #entryRemoved}. *
如果你cache的某个值需要明确释放,重写entryRemoved() *
<p>If a cache miss should be computed on demand for the corresponding keys, *
override {@link #create}. This simplifies the calling code, allowing it to *
assume a value will always be returned, even when there's a cache miss. *
如果key相对应的item丢掉啦,重写create().这简化了调用代码,即使丢失了也总会返回。 *
<p>By default, the cache size is measured in the number of entries. Override *
{@link #sizeOf} to size the cache in different units. For example, this cache *
is limited to 4MiB of bitmaps: 默认cache大小是测量的item的数量,重写sizeof计算不同item的 *
大小。 *
<pre> {@code *
int cacheSize = 4 * 1024 * 1024; // 4MiB *
LruCache<String, Bitmap> bitmapCache = new LruCache<String, Bitmap>(cacheSize) { *
protected int sizeOf(String key, Bitmap value) { *
return value.getByteCount(); *
} *
}}</pre> * *
<p>This class is thread-safe. Perform multiple cache operations atomically by *
synchronizing on the cache: <pre> {@code *
synchronized (cache) { *
if (cache.get(key) == null) { *
cache.put(key, value); *
} *
}}</pre> * *
<p>This class does not allow null to be used as a key or value. A return *
value of null from {@link #get}, {@link #put} or {@link #remove} is *
unambiguous: the key was not in the cache. *
不允许key或者value为null *
当get(),put(),remove()返回值为null时,key相应的项不在cache中 */ public
class
LruCache<K, V> { private
final
LinkedHashMap<K, V> map; /**
Size of this cache in units. Not necessarily the number of elements. */ private
int
size; //已经存储的大小 private
int
maxSize; //规定的最大存储空间 private
int
putCount; //put的次数 private
int
createCount; //create的次数 private
int
evictionCount; //回收的次数 private
int
hitCount; //命中的次数 private
int
missCount; //丢失的次数 /** *
@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<K, V>(0, 0.75f, true); } /** *
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. 通过key返回相应的item,或者创建返回相应的item。相应的item会移动到队列的头部, *
如果item的value没有被cache或者不能被创建,则返回null。 */ 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. *
如果丢失了就试图创建一个item */ 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 //如果前面存在oldValue,那么撤销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; } } /** *
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) { //返回的先前的value值 size
-= safeSizeOf(key, previous); } } if
(previous != null) { entryRemoved(false,
key, previous, value); } trimToSize(maxSize); return
previous; } /** *
@param maxSize the maximum size of the cache before returning. May be -1 *
to evict even 0-sized elements. *
清空cache空间 */ 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!"); } if
(size <= maxSize) { break; } Map.Entry<K,
V> 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); } } /** *
Removes the entry for {@code key} if it exists. *
删除key相应的cache项,返回相应的value *
@return the previous value mapped by {@code key}. */ 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) { entryRemoved(false,
key, previous, null); } return
previous; } /** *
Called for entries that have been evicted or removed. This method is *
invoked when a value is evicted to make space, removed by a call to *
{@link #remove}, or replaced by a call to {@link #put}. The default *
implementation does nothing. *
当item被回收或者删掉时调用。改方法当value被回收释放存储空间时被remove调用, *
或者替换item值时put调用,默认实现什么都没做。 *
<p>The method is called without synchronization: other threads may *
access the cache while this method is executing. * *
@param evicted true if the entry is being removed to make space, false *
if the removal was caused by a {@link #put} or {@link #remove}. *
true---为释放空间被删除;false---put或remove导致 *
@param newValue the new value for {@code key}, if it exists. If non-null, *
this removal was caused by a {@link #put}. Otherwise it was caused by *
an eviction or a {@link #remove}. */ protected
void entryRemoved(boolean evicted, K key, V oldValue, V newValue) {} /** *
Called after a cache miss to compute a value for the corresponding key. *
Returns the computed value or null if no value can be computed. The *
default implementation returns null. *
当某Item丢失时会调用到,返回计算的相应的value或者null *
<p>The method is called without synchronization: other threads may *
access the cache while this method is executing. * *
<p>If a value for {@code key} exists in the cache when this method *
returns, the created value will be released with {@link #entryRemoved} *
and discarded. This can occur when multiple threads request the same key *
at the same time (causing multiple values to be created), or when one *
thread calls {@link #put} while another is creating a value for the same *
key. */ protected
V create(K key) { return
null; } private
int safeSizeOf(K key, V value) { int
result = sizeOf(key, value); if
(result < 0) { throw
new IllegalStateException("Negative size: " + key + "=" + value); } return
result; } /** *
Returns the size of the entry for {@code key} and {@code value} in *
user-defined units. The default implementation returns 1 so that size *
is the number of entries and max size is the maximum number of entries. *
返回用户定义的item的大小,默认返回1代表item的数量,最大size就是最大item值 *
<p>An entry's size must not change while it is in the cache. */ protected
int sizeOf(K key, V value) { return
1; } /** *
Clear the cache, calling {@link #entryRemoved} on each removed entry. *
清空cacke */ public
final void evictAll() { trimToSize(-1);
// -1 will evict 0-sized elements } /** *
For caches that do not override {@link #sizeOf}, this returns the number *
of entries in the cache. For all other caches, this returns the sum of *
the sizes of the entries in this cache. */ public
synchronized final int size() { return
size; } /** *
For caches that do not override {@link #sizeOf}, this returns the maximum *
number of entries in the cache. For all other caches, this returns the *
maximum sum of the sizes of the entries in this cache. */ public
synchronized final int maxSize() { return
maxSize; } /** *
Returns the number of times {@link #get} returned a value that was *
already present in the cache. */ public
synchronized final int hitCount() { return
hitCount; } /** *
Returns the number of times {@link #get} returned null or required a new *
value to be created. */ public
synchronized final int missCount() { return
missCount; } /** *
Returns the number of times {@link #create(Object)} returned a value. */ public
synchronized final int createCount() { return
createCount; } /** *
Returns the number of times {@link #put} was called. */ public
synchronized final int putCount() { return
putCount; } /** *
Returns the number of values that have been evicted. *
返回被回收的数量 */ public
synchronized final int evictionCount() { return
evictionCount; } /** *
Returns a copy of the current contents of the cache, ordered from least *
recently accessed to most recently accessed. 返回当前cache的副本,从最近最少访问到最多访问 */ public
synchronized
final
Map<K, V> snapshot() { return
new
LinkedHashMap<K, V>(map); } @Override
public
synchronized
final
String toString() { int
accesses = hitCount + missCount; int
hitPercent = accesses != 0
? (100
* hitCount / accesses) : 0; return
String.format("LruCache[maxSize=%d,hits=%d,misses=%d,hitRate=%d%%]", maxSize,
hitCount, missCount, hitPercent); } }
本文深入探讨了LruCache内存缓存机制的工作原理、使用方法及常见API介绍,包括缓存策略、大小控制、操作方法和注意事项,旨在帮助开发者更高效地管理内存资源。
1万+

被折叠的 条评论
为什么被折叠?



