Android 源码解析: 图片加载库Picasso 2 Cache机制
Cache机制: 默认实现为LruCache,就是使用LinkedHashMap实现的一个Cache类,因此LruCache在实现的时候,其实简单理解就是将LinkedHashMap封装,然后基于LinkedHashMap的方法实现Cache的方法,在Cache的set()方法的时候,会不断计算当前还可以使用的空间大小,要是超出范围,则删除之前保存的数据。
Lrucacha,主要是get和set方法,存储的结构采用了LinkedHashMap,这种map内部实现了lru算法(Least Recently Used 近期最少使用算法)。
我们看看LinkedHashMap的实现源码:
/** A memory cache which uses a least-recently used eviction policy. */
public class LruCache implements Cache {
final LinkedHashMap<String, Bitmap> map;
final HashMap<Bitmap, int[]> gifDelay;
private final int maxSize;
private int size;
private int putCount;
private int evictionCount;
private int hitCount;
private int missCount;
/**
* Create a cache using an appropriate portion of the available RAM as the
* maximum size.
*/
public LruCache(Context context) {
this(Utils.calculateMemoryCacheSize(context));
}
/** Create a cache with a given maximum size in bytes. */
public LruCache(int maxSize) {
if (maxSize <= 0) {
throw new IllegalArgumentException("Max size must be positive.");
}
this.maxSize = maxSize;
map = new LinkedHashMap<String, Bitmap>(0, 0.75f, true);
gifDelay = new HashMap<Bitmap, int[]>();
}
@Override
public Bitmap get(String key) {
if (key == null) {
throw new NullPointerException("key == null");
}
Bitmap mapValue;
synchronized (this) {
mapValue = map.get(key);
if (mapValue != null) {
hitCount++;
return mapValue;
}
missCount++;
}
return null;
}
@Override
public void set(String key, Bitmap bitmap) {
if (key == null || bitmap == null) {
throw new NullPointerException("key == null || bitmap == null");
}
Bitmap previous;
synchronized (this) {
putCount++;
size += Utils.getBitmapBytes(bitmap);
// size += GifCache.getInstance().getRAMSize(bitmap);
previous = map.put(key, bitmap);
if (previous != null) {
size -= Utils.getBitmapBytes(previous);
// size -= GifCache.getInstance().getRAMSize(previous);
if (previous != bitmap) {
// GifCache.getInstance().remove(previous);
}
}
}
trimToSize(maxSize);
}
private void trimToSize(int maxSize) {
while (true) {
String key;
Bitmap 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<String, Bitmap> toEvict = map.entrySet().iterator().next();
key = toEvict.getKey();
value = toEvict.getValue();
map.remove(key);
size -= Utils.getBitmapBytes(value);
//
// size -= GifCache.getInstance().getRAMSize(value);
// GifCache.getInstance().remove(value);
//
evictionCount++;
}
}
}
/** Clear the cache. */
public final void evictAll() {
trimToSize(-1); // -1 will evict 0-sized elements
}
@Override
public final synchronized int size() {
return size;
}
@Override
public final synchronized int maxSize() {
return maxSize;
}
@Override
public final synchronized void clear() {
evictAll();
}
@Override
public final synchronized void clearKeyUri(String uri) {
int uriLength = uri.length();
for (Iterator<Map.Entry<String, Bitmap>> i = map.entrySet().iterator(); i
.hasNext();) {
String key = i.next().getKey();
int newlineIndex = key.indexOf(KEY_SEPARATOR);
if (newlineIndex == uriLength
&& key.substring(0, newlineIndex).equals(uri)) {
i.remove();
}
}
}
/** Returns the number of times {@link #get} returned a value. */
public final synchronized int hitCount() {
return hitCount;
}
/** Returns the number of times {@link #get} returned {@code null}. */
public final synchronized int missCount() {
return missCount;
}
/** Returns the number of times {@link #set(String, Bitmap)} was called. */
public final synchronized int putCount() {
return putCount;
}
/** Returns the number of values that have been evicted. */
public final synchronized int evictionCount() {
return evictionCount;
}
}下面是cache类的源码:/**
* A memory cache for storing the most recently used images.
* <p>
* <em>Note:</em> The {@link Cache} is accessed by multiple threads. You must
* ensure your {@link Cache} implementation is thread safe when
* {@link Cache#get(String)} or
* {@link Cache#set(String, android.graphics.Bitmap)} is called.
*/
public interface Cache {
/** Retrieve an image for the specified {@code key} or {@code null}. */
Bitmap get(String key);
/** Store an image in the cache for the specified {@code key}. */
void set(String key, Bitmap bitmap);
/** Returns the current size of the cache in bytes. */
int size();
/** Returns the maximum size in bytes that the cache can hold. */
int maxSize();
/** Clears the cache. */
void clear();
/** Remove items whose key is prefixed with {@code keyPrefix}. */
void clearKeyUri(String keyPrefix);
/** A cache which does not store any values. */
Cache NONE = new Cache() {
@Override
public Bitmap get(String key) {
return null;
}
@Override
public void set(String key, Bitmap bitmap) {
// Ignore.
}
@Override
public int size() {
return 0;
}
@Override
public int maxSize() {
return 0;
}
@Override
public void clear() {
}
@Override
public void clearKeyUri(String keyPrefix) {
}
};
}
下面是构造一个LinkedHashMap的源码:/**
* Constructs a new {@code LinkedHashMap} instance with the specified
* capacity, load factor and a flag specifying the ordering behavior.
*
* @param initialCapacity
* the initial capacity of this hash map.
* @param loadFactor
* the initial load factor.
* @param accessOrder
* {@code true} if the ordering should be done based on the last
* access (from least-recently accessed to most-recently
* accessed), and {@code false} if the ordering should be the
* order in which the entries were inserted.
* @throws IllegalArgumentException
* when the capacity is less than zero or the load factor is
* less or equal to zero.
*/
public LinkedHashMap(
int initialCapacity, float loadFactor, boolean accessOrder) {
super(initialCapacity, loadFactor);
init();
this.accessOrder = accessOrder;
}
看了上面代码,估计就很清楚了Picasso的LurCache的内部实现了。下面看看其他的LurCache的实现方法:
LinkedHashMap与HashMap的区别:
版权声明:本文为qyl10241024原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。