private final Map<String, Bitmap> cache = new HashMap<>()
private void setImage(ImageView iv, String name){
    Bitmap b = cache.get(name);
    if(b == null){
        b = loadBitmap(name);
        cache.put(name, b);
    }
    iv.setImageBitmap(b);
}
private final Map<Key, Bitmap> cache = new HashMap<>();
private void setImage(ImageView iv, String name, int width, int height){
    Key key = new Key(name, width, height);
    Bitmap b = cache.get(key);
    if(b == null){
        b = loadBitmap(name, width, height);
        cache.put(key, b);
    }
    iv.setImageBitmap(b);
}
public class Key {
    private final String name;
    private final int width;
    private final int heifht;
    public Key(String name, int width, int heifht) {
        this.name = name;
        this.width = width;
        this.heifht = heifht;
    }
    public String getName() {
        return name;
    }
    public int getWidth() {
        return width;
    }
    public int getHeifht() {
        return heifht;
    }
    @Override
    public boolean equals(Object o) {
        if (this == o) {
            return true;
        }
        if (o == null || getClass() != o.getClass()) {
            return false;
        }
        Key key = (Key) o;
        if (width != key.width) {
            return false;
        }
        if (heifht != key.heifht) {
            return false;
        }
        return name != null ? name.equals(key.name) : key.name == null;
    }
    @Override
    public int hashCode() {
        int result = name != null ? name.hashCode() : 0;
        final int prime = 31;
        result = prime * result + width;
        result = prime * result + heifht;
        return result;
    }
}

  @Override
  @NonNull
  public Bitmap get(int width, int height, Bitmap.Config config) {
    Bitmap result = getDirtyOrNull(width, height, config);
    if (result != null) {
      // Bitmaps in the pool contain random data that in some cases must be cleared for an image
      // to be rendered correctly. we shouldn‘t force all consumers to independently erase the
      // contents individually, so we do so here. See issue #131.
      result.eraseColor(Color.TRANSPARENT);
    } else {
      result = createBitmap(width, height, config);
    }
    return result;
  }
  
  
    @Nullable
  private synchronized Bitmap getDirtyOrNull(
      int width, int height, @Nullable Bitmap.Config config) {
    assertNotHardwareConfig(config);
    // 对于非公共配置类型,配置为NULL,这可能导致转换以此处请求的配置方式天真地传入NULL。
    final Bitmap result = strategy.get(width, height, config != null ? config : DEFAULT_CONFIG);
    if (result == null) {
      if (Log.isLoggable(TAG, Log.DEBUG)) {
        Log.d(TAG, "Missing bitmap=" + strategy.logBitmap(width, height, config));
      }
      misses++;
    } else {
      hits++;
      currentSize -= strategy.getSize(result);
      tracker.remove(result);
      normalize(result);
    }
    if (Log.isLoggable(TAG, Log.VERBOSE)) {
      Log.v(TAG, "Get bitmap=" + strategy.logBitmap(width, height, config));
    }
    dump();
    return result;
  }
  @Override
  @Nullable
  public Bitmap get(int width, int height, Bitmap.Config config) {
    int size = Util.getBitmapByteSize(width, height, config);
    Key bestKey = findBestKey(size, config);
    //第一处代码
    Bitmap result = groupedMap.get(bestKey);
    if (result != null) {
      decrementBitmapOfSize(bestKey.size, result);
      result.reconfigure(width, height,
          result.getConfig() != null ? result.getConfig() : Bitmap.Config.ARGB_8888);
    }
    return result;
  }
  private Key findBestKey(int size, Bitmap.Config config) {
    //第二处代码        
    Key result = keyPool.get(size, config);
    for (Bitmap.Config possibleConfig : getInConfigs(config)) {
      NavigableMap<Integer, Integer> sizesForPossibleConfig = getSizesForConfig(possibleConfig);
      Integer possibleSize = sizesForPossibleConfig.ceilingKey(size);
      if (possibleSize != null && possibleSize <= size * MAX_SIZE_MULTIPLE) {
        if (possibleSize != size
            || (possibleConfig == null ? config != null : !possibleConfig.equals(config))) {
          keyPool.offer(result);
          result = keyPool.get(possibleSize, possibleConfig);
        }
        break;
      }
    }
    return result;
  }
  
  @VisibleForTesting
  static class KeyPool extends BaseKeyPool<Key> {
    Key get(int width, int height, Bitmap.Config config) {
      Key result = get();
      result.init(width, height, config);
      return result;
    }
    @Override
    protected Key create() {
      return new Key(this);
    }
  }
  @Nullable
  public V get(K key) {
    LinkedEntry<K, V> entry = keyToEntry.get(key);
    if (entry == null) {
      entry = new LinkedEntry<>(key);
      keyToEntry.put(key, entry);
    } else {
      key.offer();
    }
    makeHead(entry);
    return entry.removeLast();
  }
/**
 * <pre>
 *     @author yangchong
 *     blog  : https://github.com/yangchong211
 *     time  : 2017/05/30
 *     desc  : 对象池抽象类
 *     revise: 具体使用方法请看:https://github.com/yangchong211/YCGallery
 * </pre>
 */
public abstract class ObjectsPool<T> {
    /*
     * 防止频繁new对象产生内存抖动.
     * 由于对象池最大长度限制,如果吞度量超过对象池容量,仍然会发生抖动.
     * 此时需要增大对象池容量,但是会占用更多内存.
     * <T> 对象池容纳的对象类型
     */
    /**
     * 对象池的最大容量
     */
    private int mSize;
    /**
     * 对象池队列
     */
    private Queue<T> mQueue;
    /**
     * 创建一个对象池
     *
     * @param size 对象池最大容量
     */
    public ObjectsPool(int size) {
        mSize = size;
        mQueue = new LinkedList<>();
    }
    /**
     * 获取一个空闲的对象
     *
     * 如果对象池为空,则对象池自己会new一个返回.
     * 如果对象池内有对象,则取一个已存在的返回.
     * take出来的对象用完要记得调用given归还.
     * 如果不归还,让然会发生内存抖动,但不会引起泄漏.
     *
     * @return 可用的对象
     *
     * @see #given(Object)
     */
    public T take() {
        //如果池内为空就创建一个
        if (mQueue.size() == 0) {
            return newInstance();
        } else {
            //对象池里有就从顶端拿出来一个返回
            return resetInstance(mQueue.poll());
        }
    }
    /**
     * 归还对象池内申请的对象
     * 如果归还的对象数量超过对象池容量,那么归还的对象就会被丢弃
     *
     * @param obj 归还的对象
     *
     * @see #take()
     */
    public void given(T obj) {
        //如果对象池还有空位子就归还对象
        if (obj != null && mQueue.size() < mSize) {
            mQueue.offer(obj);
        }
    }
    /**
     * 实例化对象
     *
     * @return 创建的对象
     */
    abstract protected T newInstance();
    /**
     * 重置对象
     *
     * 把对象数据清空到就像刚创建的一样.
     *
     * @param obj 需要被重置的对象
     * @return 被重置之后的对象
     */
    abstract protected T resetInstance(T obj);
}
public class MatrixPool extends ObjectsPool<Matrix>{
    /**
     * 矩阵对象池
     */
    public MatrixPool(int size) {
        super(size);
    }
    @Override
    protected Matrix newInstance() {
        return new Matrix();
    }
    @Override
    protected Matrix resetInstance(Matrix obj) {
        obj.reset();
        return obj;
    }
}
/**
 * 矩阵对象池
 */
private static MatrixPool mMatrixPool = new MatrixPool(16);
/**
 * 获取矩阵对象
 */
public static Matrix matrixTake() {
    return mMatrixPool.take();
}
/**
 * 获取某个矩阵的copy
 */
public static Matrix matrixTake(Matrix matrix) {
    Matrix result = mMatrixPool.take();
    if (matrix != null) {
        result.set(matrix);
    }
    return result;
}
/**
 * 归还矩阵对象
 */
public static void matrixGiven(Matrix matrix) {
    mMatrixPool.given(matrix);
}
原文:https://www.cnblogs.com/yc211/p/10685476.html