您当前的位置: 首页 >  ide

lichong951

暂无认证

  • 3浏览

    0关注

    131博文

    0收益

  • 0浏览

    0点赞

    0打赏

    0留言

私信
关注
热门博文

Glide源码阅读之策略模式3【LruPoolStrategy】

lichong951 发布时间:2022-01-10 14:01:36 ,浏览量:3

前两篇是类内部实现,LruPoolStrategy的实现不同于前面两篇,它是继承实现的,先看看LruPoolStrategy的源码

LruPoolStrategy

包路径:com.bumptech.glide.load.engine.bitmap_recycle.LruPoolStrategy


interface LruPoolStrategy {
  void put(Bitmap bitmap);

  @Nullable
  Bitmap get(int width, int height, Bitmap.Config config);

  @Nullable
  Bitmap removeLast();

  String logBitmap(Bitmap bitmap);

  String logBitmap(int width, int height, Bitmap.Config config);

  int getSize(Bitmap bitmap);
}

这个接口没有注释,挺少见的。查阅了公开文档也没有找到这个接口的说明, 看接口定义的方法也好理解,这个没有使用public来修饰,也就不对外开发了。接着看看实现类有哪些?

实现类列表
  1. 单元测试应用
  2. MockStrategy
  3. AttributeStrategy
  4. SizeConfigStrategy
  5. SizeStrategy
单元测试应用

包路径:com.bumptech.glide.load.engine.bitmap_recycle.LruBitmapPoolTest

private MockStrategy strategy;
。。。
 @Test
  public void testBitmapLargerThanPoolIsNotAdded() {
    strategy =
        new MockStrategy() {
          @Override
          public int getSize(Bitmap bitmap) {
            return 4;
          }
        };
    pool = new LruBitmapPool(3, strategy, ALLOWED_CONFIGS);
    pool.put(createMutableBitmap());
    assertEquals(0, strategy.numRemoves);
    assertEquals(0, strategy.numPuts);
  }
MockStrategy

包路径:com.bumptech.glide.load.engine.bitmap_recycle.LruBitmapPoolTest.MockStrategy

 private static class MockStrategy implements LruPoolStrategy {
    private final ArrayDeque bitmaps = new ArrayDeque();
    private int numRemoves;
    private int numPuts;

    @Override
    public void put(Bitmap bitmap) {
      numPuts++;
      bitmaps.add(bitmap);
    }

    @Override
    public Bitmap get(int width, int height, Bitmap.Config config) {
      return bitmaps.isEmpty() ? null : bitmaps.removeLast();
    }

    @Override
    public Bitmap removeLast() {
      numRemoves++;
      return bitmaps.removeLast();
    }

    @Override
    public String logBitmap(Bitmap bitmap) {
      return null;
    }

    @Override
    public String logBitmap(int width, int height, Bitmap.Config config) {
      return null;
    }

    @Override
    public int getSize(Bitmap bitmap) {
      return 1;
    }
  }

这个是用来进行单元测试的桩实现。具体实现比较简单一些,这个放在前面会好理解一些。

AttributeStrategy

包路径:com.bumptech.glide.load.engine.bitmap_recycle.AttributeStrategy

一种重用位图的策略,需要任何返回的位图的尺寸来精确匹配这些请求


/**
 * A strategy for reusing bitmaps that requires any returned bitmap's dimensions to exactly match
 * those request.
 */
 一种重用位图的策略,需要任何返回的位图的尺寸来精确匹配这些请求
class AttributeStrategy implements LruPoolStrategy {
  private final KeyPool keyPool = new KeyPool();
  private final GroupedLinkedMap groupedMap = new GroupedLinkedMap();

  @Override
  public void put(Bitmap bitmap) {
    final Key key = keyPool.get(bitmap.getWidth(), bitmap.getHeight(), bitmap.getConfig());

    groupedMap.put(key, bitmap);
  }

  @Override
  public Bitmap get(int width, int height, Bitmap.Config config) {
    final Key key = keyPool.get(width, height, config);

    return groupedMap.get(key);
  }

  @Override
  public Bitmap removeLast() {
    return groupedMap.removeLast();
  }

  @Override
  public String logBitmap(Bitmap bitmap) {
    return getBitmapString(bitmap);
  }

  @Override
  public String logBitmap(int width, int height, Bitmap.Config config) {
    return getBitmapString(width, height, config);
  }

  @Override
  public int getSize(Bitmap bitmap) {
    return Util.getBitmapByteSize(bitmap);
  }

  @Override
  public String toString() {
    return "AttributeStrategy:\n  " + groupedMap;
  }

  private static String getBitmapString(Bitmap bitmap) {
    return getBitmapString(bitmap.getWidth(), bitmap.getHeight(), bitmap.getConfig());
  }

  @SuppressWarnings("WeakerAccess")
  @Synthetic
  static String getBitmapString(int width, int height, Bitmap.Config config) {
    return "[" + width + "x" + height + "], " + config;
  }
  @VisibleForTesting
  static class KeyPool extends BaseKeyPool {
    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);
    }
  }

  @VisibleForTesting
  static class Key implements Poolable {
    private final KeyPool pool;
    private int width;
    private int height;
    // Config can be null :(
    private Bitmap.Config config;

    public Key(KeyPool pool) {
      this.pool = pool;
    }

    public void init(int width, int height, Bitmap.Config config) {
      this.width = width;
      this.height = height;
      this.config = config;
    }

    @Override
    public boolean equals(Object o) {
      if (o instanceof Key) {
        Key other = (Key) o;
        return width == other.width && height == other.height && config == other.config;
      }
      return false;
    }

    @Override
    public int hashCode() {
      int result = width;
      result = 31 * result + height;
      result = 31 * result + (config != null ? config.hashCode() : 0);
      return result;
    }

    @Override
    public String toString() {
      return getBitmapString(width, height, config);
    }

    @Override
    public void offer() {
      pool.offer(this);
    }
  }

单独看这个一个实现没发现什么特别的,接着看看下面的实现类

SizeConfigStrategy

包路径:com.bumptech.glide.load.engine.bitmap_recycle.SizeConfigStrategy

使用Bitmap. getallocationbytecount()和Bitmap键位图。从Bitmap.getConfig()返回的配置。 同时使用配置和字节大小允许我们安全地复用各种各样的位图,这提高了池的命中率,从而提高了应用程序的性能。这个类只允许复用每像素匹配字节数的位图,工作在#301左右。


/**
 * Keys {@link android.graphics.Bitmap Bitmaps} using both {@link
 * android.graphics.Bitmap#getAllocationByteCount()} and the {@link android.graphics.Bitmap.Config}
 * returned from {@link android.graphics.Bitmap#getConfig()}.
 *
 * 

Using both the config and the byte size allows us to safely re-use a greater variety of {@link * android.graphics.Bitmap Bitmaps}, which increases the hit rate of the pool and therefore the * performance of applications. This class works around #301 by only allowing re-use of {@link * android.graphics.Bitmap Bitmaps} with a matching number of bytes per pixel. */ 使用Bitmap. getallocationbytecount()和Bitmap键位图。从Bitmap.getConfig()返回的配置。 同时使用配置和字节大小允许我们安全地复用各种各样的位图,这提高了池的命中率,从而提高了应用程序的性能。这个类只允许复用每像素匹配字节数的位图,工作在#301左右。 @RequiresApi(Build.VERSION_CODES.KITKAT) public class SizeConfigStrategy implements LruPoolStrategy { private static final int MAX_SIZE_MULTIPLE = 8; private static final Bitmap.Config[] ARGB_8888_IN_CONFIGS; static { Bitmap.Config[] result = new Bitmap.Config[] { Bitmap.Config.ARGB_8888, // The value returned by Bitmaps with the hidden Bitmap config. null, }; if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { result = Arrays.copyOf(result, result.length + 1); result[result.length - 1] = Config.RGBA_F16; } ARGB_8888_IN_CONFIGS = result; } private static final Bitmap.Config[] RGBA_F16_IN_CONFIGS = ARGB_8888_IN_CONFIGS; // We probably could allow ARGB_4444 and RGB_565 to decode into each other, but ARGB_4444 is // deprecated and we'd rather be safe. private static final Bitmap.Config[] RGB_565_IN_CONFIGS = new Bitmap.Config[] {Bitmap.Config.RGB_565}; private static final Bitmap.Config[] ARGB_4444_IN_CONFIGS = new Bitmap.Config[] {Bitmap.Config.ARGB_4444}; private static final Bitmap.Config[] ALPHA_8_IN_CONFIGS = new Bitmap.Config[] {Bitmap.Config.ALPHA_8}; private final KeyPool keyPool = new KeyPool(); private final GroupedLinkedMap groupedMap = new GroupedLinkedMap(); private final Map sortedSizes = new HashMap(); @Override public void put(Bitmap bitmap) { int size = Util.getBitmapByteSize(bitmap); Key key = keyPool.get(size, bitmap.getConfig()); groupedMap.put(key, bitmap); NavigableMap sizes = getSizesForConfig(bitmap.getConfig()); Integer current = sizes.get(key.size); sizes.put(key.size, current == null ? 1 : current + 1); } @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) { // Decrement must be called before reconfigure. decrementBitmapOfSize(bestKey.size, result); result.reconfigure(width, height, config); } return result; } private Key findBestKey(int size, Bitmap.Config config) { Key result = keyPool.get(size, config); for (Bitmap.Config possibleConfig : getInConfigs(config)) { NavigableMap sizesForPossibleConfig = getSizesForConfig(possibleConfig); Integer possibleSize = sizesForPossibleConfig.ceilingKey(size); if (possibleSize != null && possibleSize = Build.VERSION_CODES.O) { if (Bitmap.Config.RGBA_F16.equals(requested)) { // NOPMD - Avoid short circuiting sdk checks. return RGBA_F16_IN_CONFIGS; } } switch (requested) { case ARGB_8888: return ARGB_8888_IN_CONFIGS; case RGB_565: return RGB_565_IN_CONFIGS; case ARGB_4444: return ARGB_4444_IN_CONFIGS; case ALPHA_8: return ALPHA_8_IN_CONFIGS; default: return new Bitmap.Config[] {requested}; } } }

AttributeStrategy#put(Bitmap bitmap) VS SizeConfigStrategy#put(Bitmap bitmap)

AttributeStrategy

public void put(Bitmap bitmap) {
    final Key key = keyPool.get(bitmap.getWidth(), bitmap.getHeight(), bitmap.getConfig());

    groupedMap.put(key, bitmap);
  }

SizeConfigStrategy

 @Override
  public void put(Bitmap bitmap) {
    int size = Util.getBitmapByteSize(bitmap);
    Key key = keyPool.get(size, bitmap.getConfig());

    groupedMap.put(key, bitmap);

    NavigableMap sizes = getSizesForConfig(bitmap.getConfig());
    Integer current = sizes.get(key.size);
    sizes.put(key.size, current == null ? 1 : current + 1);
  }

很显然算法策略输入参数不一样, AttributeStrategy的key由bitmap的属性Width、Height、Config SizeConfigStrategy的key由bitmap的size、config组成 相对比较一下SizeConfigStrategy安全性比较高一些。但计算性能方面会消耗大一些,其他方法实现与各自的put(Bitmap bitmap)保持一致,这里不具体说明了。 再看一个

SizeStrategy

包路径:com.bumptech.glide.load.engine.bitmap_recycle.SizeStrategy 这个策略并没有对外公开,但看其具体实现和SizeConfigStrategy相似度较高。和其他两个比较着看会好理解一些

基于Bitmap#reconfigure(int, int,Bitmap.Config)的位图复用策略


/**
 * A strategy for reusing bitmaps that relies on {@link Bitmap#reconfigure(int, int,
 * Bitmap.Config)}.
 *
 * 

Requires {@link Build.VERSION_CODES#KITKAT KitKat} or higher. */ @RequiresApi(Build.VERSION_CODES.KITKAT) final class SizeStrategy implements LruPoolStrategy { private static final int MAX_SIZE_MULTIPLE = 8; private final KeyPool keyPool = new KeyPool(); private final GroupedLinkedMap groupedMap = new GroupedLinkedMap(); private final NavigableMap sortedSizes = new PrettyPrintTreeMap(); @Override public void put(Bitmap bitmap) { int size = Util.getBitmapByteSize(bitmap); final Key key = keyPool.get(size); groupedMap.put(key, bitmap); Integer current = sortedSizes.get(key.size); sortedSizes.put(key.size, current == null ? 1 : current + 1); } @Override @Nullable public Bitmap get(int width, int height, Bitmap.Config config) { final int size = Util.getBitmapByteSize(width, height, config); Key key = keyPool.get(size); Integer possibleSize = sortedSizes.ceilingKey(size); if (possibleSize != null && possibleSize != size && possibleSize

关注
打赏
1659512212
查看更多评论
0.1047s