Android 源码解析: 图片加载库Picasso 2 Cache机制

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的实现方法:







版权声明:本文为qyl10241024原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。