aboutsummaryrefslogtreecommitdiff
path: root/library/src/com/bumptech/glide/resize/bitmap_recycle/SizeStrategy.java
diff options
context:
space:
mode:
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.java175
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);
+ }
+ }
+}