diff options
Diffstat (limited to 'library/src/com/bumptech/glide/resize/bitmap_recycle/SizeStrategy.java')
-rw-r--r-- | library/src/com/bumptech/glide/resize/bitmap_recycle/SizeStrategy.java | 175 |
1 files changed, 175 insertions, 0 deletions
diff --git a/library/src/com/bumptech/glide/resize/bitmap_recycle/SizeStrategy.java b/library/src/com/bumptech/glide/resize/bitmap_recycle/SizeStrategy.java new file mode 100644 index 00000000..f8778772 --- /dev/null +++ b/library/src/com/bumptech/glide/resize/bitmap_recycle/SizeStrategy.java @@ -0,0 +1,175 @@ +package com.bumptech.glide.resize.bitmap_recycle; + +import android.annotation.TargetApi; +import android.graphics.Bitmap; + +import java.util.TreeMap; + +@TargetApi(19) +class SizeStrategy implements LruPoolStrategy { + private static final int MAX_SIZE_MULTIPLE = 4; + private final KeyPool keyPool = new KeyPool(); + private final GroupedLinkedMap<Key, Bitmap> groupedMap = new GroupedLinkedMap<Key, Bitmap>(); + private final TreeMap<Integer, Integer> sortedSizes = new TreeMap<Integer, Integer>(); + + @Override + public void put(Bitmap bitmap) { + final Key key = keyPool.get(bitmap.getAllocationByteCount()); + + groupedMap.put(key, bitmap); + + Integer current = sortedSizes.get(key.size); + sortedSizes.put(key.size, current == null ? 1 : current + 1); + } + + @Override + public Bitmap get(int width, int height, Bitmap.Config config) { + final int size = getSize(width, height, config); + Key key = keyPool.get(size); + + Integer possibleSize = sortedSizes.ceilingKey(size); + if (possibleSize != null && possibleSize != size && possibleSize <= size * MAX_SIZE_MULTIPLE) { + keyPool.offer(key); + key = keyPool.get(possibleSize); + } + + // Do a get even if we know we don't have a bitmap so that the key moves to the front in the lru pool + final Bitmap result = groupedMap.get(key); + if (result != null) { + result.reconfigure(width, height, config); + decrementBitmapOfSize(possibleSize); + } + + return result; + } + + @Override + public Bitmap removeLast() { + Bitmap removed = groupedMap.removeLast(); + if (removed != null) { + final int removedSize = removed.getAllocationByteCount(); + decrementBitmapOfSize(removedSize); + } + return removed; + } + + private void decrementBitmapOfSize(Integer size) { + Integer current = sortedSizes.get(size); + if (current == 1) { + sortedSizes.remove(size); + } else { + sortedSizes.put(size, current - 1); + } + } + + @Override + public String logBitmap(Bitmap bitmap) { + return getBitmapString(bitmap); + } + + @Override + public String logBitmap(int width, int height, Bitmap.Config config) { + return getBitmapString(getSize(width, height, config)); + } + + @Override + public int getSize(Bitmap bitmap) { + return bitmap.getAllocationByteCount(); + } + + @Override + public String toString() { + String result = "SizeStrategy:\n " + groupedMap + "\n SortedSizes( "; + boolean hadAtLeastOneKey = false; + for (Integer size : sortedSizes.keySet()) { + hadAtLeastOneKey = true; + result += "{" + getBitmapString(size) + ":" + sortedSizes.get(size) + "}, "; + } + if (hadAtLeastOneKey) { + result = result.substring(0, result.length() - 2); + } + return result + " )"; + } + + private static String getBitmapString(Bitmap bitmap) { + return getBitmapString(bitmap.getAllocationByteCount()); + } + + private static String getBitmapString(int size) { + return "[" + size + "]"; + } + + private static int getSize(int width, int height, Bitmap.Config config) { + return width * height * getBytesPerPixel(config); + } + + private static int getBytesPerPixel(Bitmap.Config config) { + switch (config) { + case ARGB_8888: + return 4; + case RGB_565: + return 2; + case ARGB_4444: + return 2; + case ALPHA_8: + return 1; + default: + // We only use this to calculate sizes to get, so choosing 4 bytes per pixel is conservative and + // probably forces us to get a larger bitmap than we really need. Since we can't tell for sure, probably + // better safe than sorry. + return 4; + } + } + + private static class KeyPool extends BaseKeyPool<Key> { + + public Key get(int size) { + Key result = get(); + result.init(size); + return result; + } + + @Override + protected Key create() { + return new Key(this); + } + } + + private static class Key implements Poolable { + private final KeyPool pool; + private int size; + + private Key(KeyPool pool) { + this.pool = pool; + } + + public void init(int size) { + this.size = size; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + + Key key = (Key) o; + + return size == key.size; + } + + @Override + public int hashCode() { + return size; + } + + @Override + public String toString() { + return getBitmapString(size); + } + + @Override + public void offer() { + pool.offer(this); + } + } +} |