aboutsummaryrefslogtreecommitdiff
path: root/library
diff options
context:
space:
mode:
Diffstat (limited to 'library')
-rw-r--r--library/.gitignore2
-rw-r--r--library/lint.xml1
-rw-r--r--library/src/com/bumptech/glide/resize/bitmap_recycle/AttributeStrategy.java117
-rw-r--r--library/src/com/bumptech/glide/resize/bitmap_recycle/BaseKeyPool.java36
-rw-r--r--library/src/com/bumptech/glide/resize/bitmap_recycle/GroupedLinkedMap.java146
-rw-r--r--library/src/com/bumptech/glide/resize/bitmap_recycle/LruBitmapPool.java247
-rw-r--r--library/src/com/bumptech/glide/resize/bitmap_recycle/LruPoolStrategy.java12
-rw-r--r--library/src/com/bumptech/glide/resize/bitmap_recycle/Poolable.java5
-rw-r--r--library/src/com/bumptech/glide/resize/bitmap_recycle/SizeStrategy.java175
-rw-r--r--library/tests/src/com/bumptech/glide/LruBitmapPoolTest.java162
-rw-r--r--library/tests/src/com/bumptech/glide/resize/bitmap_recycle/AttributeStrategyTest.java87
-rw-r--r--library/tests/src/com/bumptech/glide/resize/bitmap_recycle/LruBitmapPoolTest.java145
-rw-r--r--library/tests/src/com/bumptech/glide/resize/bitmap_recycle/SizeStrategyTest.java105
13 files changed, 881 insertions, 359 deletions
diff --git a/library/.gitignore b/library/.gitignore
index ed6b3e00..1cf16874 100644
--- a/library/.gitignore
+++ b/library/.gitignore
@@ -1,4 +1,6 @@
tests/ant.properties
tests/local.properties
tests/gen/**/*
+tests/bin
+libs/volley.jar
diff --git a/library/lint.xml b/library/lint.xml
index 2d559c9d..558db4f5 100644
--- a/library/lint.xml
+++ b/library/lint.xml
@@ -4,5 +4,6 @@
<issue id="AllowBackup" severity="ignore" />
<issue id="InlinedApi">
<ignore path="src/com/bumptech/glide/resize/cache/LruMemoryCache.java" />
+ <ignore path="src/com/bumptech/glide/resize/bitmap_recycle/LruBitmapPool.java" />
</issue>
</lint>
diff --git a/library/src/com/bumptech/glide/resize/bitmap_recycle/AttributeStrategy.java b/library/src/com/bumptech/glide/resize/bitmap_recycle/AttributeStrategy.java
new file mode 100644
index 00000000..bb3d3e1a
--- /dev/null
+++ b/library/src/com/bumptech/glide/resize/bitmap_recycle/AttributeStrategy.java
@@ -0,0 +1,117 @@
+package com.bumptech.glide.resize.bitmap_recycle;
+
+import android.graphics.Bitmap;
+
+class AttributeStrategy implements LruPoolStrategy {
+ private final KeyPool keyPool = new KeyPool();
+ private final GroupedLinkedMap<Key, Bitmap> groupedMap = new GroupedLinkedMap<Key, Bitmap>();
+
+ 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 bitmap.getHeight() * bitmap.getRowBytes();
+ }
+
+ @Override
+ public String toString() {
+ return "AttributeStrategy:\n " + groupedMap;
+ }
+
+ private static String getBitmapString(Bitmap bitmap) {
+ return getBitmapString(bitmap.getWidth(), bitmap.getHeight(), bitmap.getConfig());
+ }
+
+ private static String getBitmapString(int width, int height, Bitmap.Config config) {
+ return "[" + width + "x" + height + "], " + config;
+ }
+
+ private static class KeyPool extends BaseKeyPool<Key> {
+ public 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);
+ }
+ }
+
+ private 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 (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+
+ Key key = (Key) o;
+
+ if (height != key.height) return false;
+ if (width != key.width) return false;
+ if (config != key.config) return false;
+
+ return true;
+ }
+
+ @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);
+ }
+ }
+}
diff --git a/library/src/com/bumptech/glide/resize/bitmap_recycle/BaseKeyPool.java b/library/src/com/bumptech/glide/resize/bitmap_recycle/BaseKeyPool.java
new file mode 100644
index 00000000..186850b8
--- /dev/null
+++ b/library/src/com/bumptech/glide/resize/bitmap_recycle/BaseKeyPool.java
@@ -0,0 +1,36 @@
+package com.bumptech.glide.resize.bitmap_recycle;
+
+import android.os.Build;
+
+import java.util.ArrayDeque;
+import java.util.LinkedList;
+import java.util.Queue;
+
+abstract class BaseKeyPool<T extends Poolable> {
+ private static final int MAX_SIZE = 20;
+ private final Queue<T> keyPool;
+
+ public BaseKeyPool() {
+ if (Build.VERSION.SDK_INT >= 9) {
+ keyPool = new ArrayDeque<T>(MAX_SIZE);
+ } else {
+ keyPool = new LinkedList<T>();
+ }
+ }
+
+ protected T get() {
+ T result = keyPool.poll();
+ if (result == null) {
+ result = create();
+ }
+ return result;
+ }
+
+ public void offer(T key) {
+ if (keyPool.size() < MAX_SIZE) {
+ keyPool.offer(key);
+ }
+ }
+
+ protected abstract T create();
+}
diff --git a/library/src/com/bumptech/glide/resize/bitmap_recycle/GroupedLinkedMap.java b/library/src/com/bumptech/glide/resize/bitmap_recycle/GroupedLinkedMap.java
new file mode 100644
index 00000000..5fef781b
--- /dev/null
+++ b/library/src/com/bumptech/glide/resize/bitmap_recycle/GroupedLinkedMap.java
@@ -0,0 +1,146 @@
+package com.bumptech.glide.resize.bitmap_recycle;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * Similar to {@link java.util.LinkedHashMap} when access ordered except that it is access ordered on groups
+ * of bitmaps rather than individual objects. The idea is to be able to find the LRU bitmap size, rather than the
+ * LRU bitmap object. We can then remove bitmaps from the least recently used size of bitmap when we need to
+ * reduce our cache size.
+ *
+ * For the purposes of the LRU, we count gets for a particular size of bitmap as an access, even if no bitmaps
+ * of that size are present. We do not count addition or removal of bitmaps as an access.
+ */
+class GroupedLinkedMap<K extends Poolable, V> {
+ private final LinkedEntry<K, V> head = new LinkedEntry<K, V>();
+ private final Map<K, LinkedEntry<K, V>> keyToEntry = new HashMap<K, LinkedEntry<K, V>>();
+
+ public void put(K key, V value) {
+ LinkedEntry<K, V> entry = keyToEntry.get(key);
+
+ if (entry == null) {
+ entry = new LinkedEntry<K, V>(key);
+ makeTail(entry);
+ keyToEntry.put(key, entry);
+ } else {
+ key.offer();
+ }
+
+ entry.add(value);
+ }
+
+ public V get(K key) {
+ LinkedEntry<K, V> entry = keyToEntry.get(key);
+ if (entry == null) {
+ entry = new LinkedEntry<K, V>(key);
+ keyToEntry.put(key, entry);
+ } else {
+ key.offer();
+ }
+
+ makeHead(entry);
+
+ return entry.removeLast();
+ }
+
+ public V removeLast() {
+ LinkedEntry<K, V> last = head.prev;
+
+ while (last != head) {
+ V removed = last.removeLast();
+ if (removed != null) {
+ return removed;
+ } else {
+ // We will clean up empty lru entries since they are likely to have been one off or unusual sizes and
+ // are not likely to be requested again so the gc thrash should be minimal. Doing so will speed up our
+ // removeLast operation in the future and prevent our linked list from growing to arbitrarily large
+ // sizes.
+ removeEntry(last);
+ keyToEntry.remove(last.key);
+ last.key.offer();
+ }
+
+ last = last.prev;
+ }
+
+ return null;
+ }
+
+ @Override
+ public String toString() {
+ String result = "GroupedLinkedMap( ";
+ LinkedEntry<K, V> current = head.next;
+ boolean hadAtLeastOneItem = false;
+ while (current != head) {
+ hadAtLeastOneItem = true;
+ result += "{" + current.key + ":" + current.size() + "}, ";
+ current = current.next;
+ }
+ if (hadAtLeastOneItem) {
+ result = result.substring(0, result.length() - 2);
+ }
+ return result + " )";
+ }
+
+ // Make the entry the most recently used item.
+ private void makeHead(LinkedEntry<K, V> entry) {
+ removeEntry(entry);
+ entry.prev = head;
+ entry.next = head.next;
+ updateEntry(entry);
+ }
+
+ // Make the entry the least recently used item.
+ private void makeTail(LinkedEntry<K, V> entry) {
+ removeEntry(entry);
+ entry.prev = head.prev;
+ entry.next = head;
+ updateEntry(entry);
+ }
+
+ private static void updateEntry(LinkedEntry entry) {
+ entry.next.prev = entry;
+ entry.prev.next = entry;
+ }
+
+ private static void removeEntry(LinkedEntry entry) {
+ entry.prev.next = entry.next;
+ entry.next.prev = entry.prev;
+ }
+
+ private static class LinkedEntry<K, V> {
+ private final K key;
+ private List<V> values;
+ LinkedEntry<K, V> next;
+ LinkedEntry<K, V> prev;
+
+ // Used only for the first item in the list which we will treat specially and which will not contain a value.
+ public LinkedEntry() {
+ this(null);
+ }
+
+ public LinkedEntry(K key) {
+ next = prev = this;
+ this.key = key;
+ }
+
+ public V removeLast() {
+ final int valueSize = size();
+ return valueSize > 0 ? values.remove(valueSize - 1) : null;
+ }
+
+ public int size() {
+ return values != null ? values.size() : 0;
+ }
+
+ public void add(V value) {
+ if (values == null) {
+ values = new ArrayList<V>();
+ }
+ values.add(value);
+ }
+ }
+}
diff --git a/library/src/com/bumptech/glide/resize/bitmap_recycle/LruBitmapPool.java b/library/src/com/bumptech/glide/resize/bitmap_recycle/LruBitmapPool.java
index 4682271f..f4fc9be5 100644
--- a/library/src/com/bumptech/glide/resize/bitmap_recycle/LruBitmapPool.java
+++ b/library/src/com/bumptech/glide/resize/bitmap_recycle/LruBitmapPool.java
@@ -5,34 +5,52 @@ import static android.content.ComponentCallbacks2.TRIM_MEMORY_MODERATE;
import android.graphics.Bitmap;
import android.util.Log;
-
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.LinkedList;
-import java.util.List;
-import java.util.Map;
-import java.util.Queue;
+import android.os.Build;
public class LruBitmapPool implements BitmapPool {
private static final String TAG = "LruBitmapPool";
- private final GroupedBitmapLinkedMap pool = new GroupedBitmapLinkedMap();
+ private final LruPoolStrategy strategy;
private final int maxSize;
private int currentSize = 0;
+ private int hits;
+ private int misses;
+ private int puts;
+ private int evictions;
+
+ // Exposed for testing only.
+ LruBitmapPool(int maxSize, LruPoolStrategy strategy) {
+ this.maxSize = maxSize;
+ this.strategy = strategy;
+ }
public LruBitmapPool(int maxSize) {
this.maxSize = maxSize;
+ if (Build.VERSION.SDK_INT >= 19) {
+ strategy = new SizeStrategy();
+ } else {
+ strategy = new AttributeStrategy();
+ }
}
@Override
public synchronized boolean put(Bitmap bitmap) {
- final int size = getSize(bitmap);
+ if (!bitmap.isMutable() || strategy.getSize(bitmap) > maxSize) {
+ return false;
+ }
- pool.put(bitmap);
+ final int size = strategy.getSize(bitmap);
+ strategy.put(bitmap);
+ puts++;
currentSize += size;
- evict();
+ if (Log.isLoggable(TAG, Log.DEBUG)) {
+ Log.d(TAG, "Put bitmap in pool=" + strategy.logBitmap(bitmap));
+ }
+ dump();
+
+ evict();
return true;
}
@@ -42,14 +60,20 @@ public class LruBitmapPool implements BitmapPool {
@Override
public synchronized Bitmap get(int width, int height, Bitmap.Config config) {
- final Bitmap result = pool.get(width, height, config);
+ final Bitmap result = strategy.get(width, height, config);
if (result == null) {
if (Log.isLoggable(TAG, Log.DEBUG)) {
- Log.d(TAG, "Missing bitmap with dimens=[" + width + "x" + height + "] and config config=" + config);
+ Log.d(TAG, "Missing bitmap=" + strategy.logBitmap(width, height, config));
}
+ misses++;
} else {
- currentSize -= getSize(result);
+ hits++;
+ currentSize -= strategy.getSize(result);
}
+ if (Log.isLoggable(TAG, Log.DEBUG)) {
+ Log.d(TAG, "Get bitmap=" + strategy.logBitmap(width, height, config));
+ }
+ dump();
return result;
}
@@ -64,198 +88,27 @@ public class LruBitmapPool implements BitmapPool {
if (level >= TRIM_MEMORY_MODERATE) {
clearMemory();
} else if (level >= TRIM_MEMORY_BACKGROUND) {
- trimToSize(currentSize / 2);
+ trimToSize(maxSize / 2);
}
}
private void trimToSize(int size) {
while (currentSize > size) {
- final Bitmap removed = pool.removeLast();
- currentSize -= getSize(removed);
+ final Bitmap removed = strategy.removeLast();
+ currentSize -= strategy.getSize(removed);
removed.recycle();
- }
- }
-
- private static int getSize(Bitmap bitmap) {
- return bitmap.getHeight() * bitmap.getRowBytes();
- }
-
- /**
- * Similar to {@link java.util.LinkedHashMap} when access ordered except that it is access ordered on groups
- * of bitmaps rather than individual objects. The idea is to be able to find the LRU bitmap size, rather than the
- * LRU bitmap object. We can then remove bitmaps from the least recently used size of bitmap when we need to
- * reduce our cache size.
- *
- * For the purposes of the LRU, we count gets for a particular size of bitmap as an access, even if no bitmaps
- * of that size are present. We do not count addition or removal of bitmaps as an access.
- */
- private static class GroupedBitmapLinkedMap {
- private final Map<Key, LinkedEntry> keyToEntry = new HashMap<Key, LinkedEntry>();
- private final LinkedEntry head = new LinkedEntry();
- private final KeyPool keyPool = new KeyPool();
-
- private static class KeyPool {
- private static final int MAX_SIZE = 20;
-
- private final Queue<Key> keyPool = new LinkedList<Key>();
-
- public Key get(int width, int height, Bitmap.Config config) {
- Key result = keyPool.poll();
- if (result == null) {
- result = new Key();
- }
- result.init(width, height, config);
- return result;
- }
-
- public void offer(Key key) {
- if (keyPool.size() <= MAX_SIZE) {
- keyPool.offer(key);
- }
- }
- }
-
- private static class Key {
- private int width;
- private int height;
- private Bitmap.Config config; //this can be null :(
-
- 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 (this == o) return true;
- if (o == null || getClass() != o.getClass()) return false;
-
- Key key = (Key) o;
-
- if (height != key.height) return false;
- if (width != key.width) return false;
- if (config != key.config) return false;
-
- return true;
- }
-
- @Override
- public int hashCode() {
- int result = width;
- result = 31 * result + height;
- result = 31 * result + (config != null ? config.hashCode() : 0);
- return result;
- }
- }
-
- public void put(Bitmap bitmap) {
- final Key key = keyPool.get(bitmap.getWidth(), bitmap.getHeight(), bitmap.getConfig());
-
- LinkedEntry entry = keyToEntry.get(key);
- if (entry == null) {
- entry = new LinkedEntry(key);
- makeTail(entry);
- keyToEntry.put(key, entry);
- } else {
- keyPool.offer(key);
- }
-
- entry.add(bitmap);
- }
-
- public Bitmap get(int width, int height, Bitmap.Config config) {
- final Key key = keyPool.get(width, height, config);
-
- LinkedEntry entry = keyToEntry.get(key);
- if (entry == null) {
- entry = new LinkedEntry(key);
- keyToEntry.put(key, entry);
- } else {
- keyPool.offer(key);
- }
-
- makeHead(entry);
-
- return entry.removeLast();
- }
-
- public Bitmap removeLast() {
- LinkedEntry last = head.prev;
-
- while (last != head) {
- Bitmap removed = last.removeLast();
- if (removed != null) {
- return removed;
- } else {
- //we will clean up empty lru entries since they are likely to have been one off or unusual sizes
- //and are not likely to be requested again so the gc thrash should be minimal. Doing so will speed
- //up our removeLast operation in the future and prevent our linked list from growing to arbitrarily
- //large sizes
- removeEntry(last);
- keyToEntry.remove(last.key);
- keyPool.offer(last.key);
- }
-
- last = last.prev;
+ evictions++;
+ if (Log.isLoggable(TAG, Log.DEBUG)) {
+ Log.d(TAG, "Evicting bitmap=" + strategy.logBitmap(removed));
}
-
- return null;
+ dump();
}
+ }
- private void makeHead(LinkedEntry entry) {
- removeEntry(entry);
- entry.prev = head;
- entry.next = head.next;
- updateEntry(entry);
- }
-
- private void makeTail(LinkedEntry entry) {
- removeEntry(entry);
- entry.prev = head.prev;
- entry.next = head;
- updateEntry(entry);
- }
-
- //after updating entry's next and prev, set
- //those entry's prev and next (respectively) to rentry
- private static void updateEntry(LinkedEntry entry) {
- entry.next.prev = entry;
- entry.prev.next = entry;
- }
-
- private static void removeEntry(LinkedEntry entry) {
- entry.prev.next = entry.next;
- entry.next.prev = entry.prev;
- }
-
- private static class LinkedEntry {
- private List<Bitmap> value;
- private final Key key;
- LinkedEntry next;
- LinkedEntry prev;
-
- //head only
- public LinkedEntry() {
- this(null);
- }
-
- public LinkedEntry(Key key) {
- next = prev = this;
- this.key = key;
- }
-
- public Bitmap removeLast() {
- final int valueSize = value != null ? value.size() : 0;
- return valueSize > 0 ? value.remove(valueSize-1) : null;
- }
-
- public void add(Bitmap bitmap) {
- if (value == null) {
- value = new ArrayList<Bitmap>();
- }
- value.add(bitmap);
- }
+ private void dump() {
+ if (Log.isLoggable(TAG, Log.VERBOSE)) {
+ Log.v(TAG, "Hits=" + hits + " misses=" + misses + " puts=" + puts + " evictions=" + evictions + " currentSize="
+ + currentSize + " maxSize=" + maxSize + "\nStrategy=" + strategy);
}
}
}
diff --git a/library/src/com/bumptech/glide/resize/bitmap_recycle/LruPoolStrategy.java b/library/src/com/bumptech/glide/resize/bitmap_recycle/LruPoolStrategy.java
new file mode 100644
index 00000000..359af6e4
--- /dev/null
+++ b/library/src/com/bumptech/glide/resize/bitmap_recycle/LruPoolStrategy.java
@@ -0,0 +1,12 @@
+package com.bumptech.glide.resize.bitmap_recycle;
+
+import android.graphics.Bitmap;
+
+interface LruPoolStrategy {
+ public void put(Bitmap bitmap);
+ public Bitmap get(int width, int height, Bitmap.Config config);
+ public Bitmap removeLast();
+ public String logBitmap(Bitmap bitmap);
+ public String logBitmap(int width, int height, Bitmap.Config config);
+ public int getSize(Bitmap bitmap);
+}
diff --git a/library/src/com/bumptech/glide/resize/bitmap_recycle/Poolable.java b/library/src/com/bumptech/glide/resize/bitmap_recycle/Poolable.java
new file mode 100644
index 00000000..33a5abb7
--- /dev/null
+++ b/library/src/com/bumptech/glide/resize/bitmap_recycle/Poolable.java
@@ -0,0 +1,5 @@
+package com.bumptech.glide.resize.bitmap_recycle;
+
+interface Poolable {
+ public void offer();
+}
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);
+ }
+ }
+}
diff --git a/library/tests/src/com/bumptech/glide/LruBitmapPoolTest.java b/library/tests/src/com/bumptech/glide/LruBitmapPoolTest.java
deleted file mode 100644
index 767403ef..00000000
--- a/library/tests/src/com/bumptech/glide/LruBitmapPoolTest.java
+++ /dev/null
@@ -1,162 +0,0 @@
-package com.bumptech.glide;
-
-import android.content.ComponentCallbacks2;
-import android.graphics.Bitmap;
-import android.test.AndroidTestCase;
-import com.bumptech.glide.resize.bitmap_recycle.LruBitmapPool;
-
-import java.util.ArrayList;
-import java.util.List;
-
-public class LruBitmapPoolTest extends AndroidTestCase {
- private static final int SIZE = 1024 * 1024;
- private LruBitmapPool pool;
-
- @Override
- protected void setUp() throws Exception {
- super.setUp();
- pool = new LruBitmapPool(SIZE);
- }
-
- public void testCanAddAndRemoveBitmap() {
- Bitmap bitmap = getBitmap();
- pool.put(bitmap);
- assertEquals(bitmap, getEquivalentFromPool(bitmap));
- }
-
- public void testCanAddAndRemoveBitmapsOfDifferentSizes() {
- Bitmap first = Bitmap.createBitmap(100, 100, Bitmap.Config.ARGB_8888);
- Bitmap second = Bitmap.createBitmap(100, 200, Bitmap.Config.ARGB_8888);
- pool.put(first);
- pool.put(second);
- assertEquals(first, getEquivalentFromPool(first));
- assertEquals(second, getEquivalentFromPool(second));
- }
-
- public void testCanAddAndRemoveBitmapsOfDifferentConfigs() {
- Bitmap first = Bitmap.createBitmap(100, 100, Bitmap.Config.ARGB_8888);
- Bitmap second = Bitmap.createBitmap(100, 100, Bitmap.Config.RGB_565);
- pool.put(first);
- pool.put(second);
- assertEquals(first, getEquivalentFromPool(first));
- assertEquals(second, getEquivalentFromPool(second));
- }
-
- public void testPoolIsSizeLimited() {
- List<Bitmap> bitmaps = fillPool();
- Bitmap first = bitmaps.get(0);
- pool.put(Bitmap.createBitmap(first));
-
- int totalInPool = 0;
- for (int i = 0; i < bitmaps.size(); i++) {
- if (getEquivalentFromPool(first) == null) {
- break;
- }
- totalInPool++;
- }
-
- assertEquals(bitmaps.size(), totalInPool);
- }
-
- public void testLeastRecentlyAcquiredBitmapRemovedFirst() {
- Bitmap special = Bitmap.createBitmap(100, 100, Bitmap.Config.RGB_565);
- pool.put(Bitmap.createBitmap(special));
- pool.put(Bitmap.createBitmap(special));
- getEquivalentFromPool(special);
- List<Bitmap> bitmaps = fillPool();
-
- assertNotNull(getEquivalentFromPool(special));
-
- Bitmap first = bitmaps.get(0);
- int totalAcquired = 0;
- for (int i = 0; i < bitmaps.size(); i++) {
- if (getEquivalentFromPool(first) == null) {
- break;
- }
- totalAcquired++;
- }
-
- assertEquals(totalAcquired, bitmaps.size() - 1);
- }
-
- public void testTrimMemoryCompleteClearsPool() {
- doTestTrimMemory(ComponentCallbacks2.TRIM_MEMORY_COMPLETE, false);
- }
-
- public void testTrimMemoryModerateClearsPool() {
- doTestTrimMemory(ComponentCallbacks2.TRIM_MEMORY_MODERATE, false);
- }
-
- public void testTrimMemoryBackgroundRemovesHalf() {
- doTestTrimMemory(ComponentCallbacks2.TRIM_MEMORY_BACKGROUND, true);
- }
-
- private void doTestTrimMemory(int level, boolean half) {
- List<Bitmap> bitmaps = fillPool();
- Bitmap first = bitmaps.get(0);
- assertTrue(bitmaps.size() >= 2);
-
- Bitmap fromPool = getEquivalentFromPool(first);
- assertNotNull(fromPool);
- pool.put(fromPool);
- pool.trimMemory(level);
- if (half) {
- for (int i = 0; i < bitmaps.size() / 2; i++) {
- assertNotNull(getEquivalentFromPool(first));
- }
- }
- assertNull(getEquivalentFromPool(first));
- }
-
- public void testClearMemoryRemovesAllBitmaps() {
- List<Bitmap> bitmaps = fillPool();
- assertTrue(bitmaps.size() >= 2);
-
- Bitmap first = bitmaps.get(0);
- assertNotNull(getEquivalentFromPool(first));
- pool.clearMemory();
- assertNull(getEquivalentFromPool(first));
- }
-
- public void testTrimMemoryCallsRecycleOnRemovedBitmaps() {
- List<Bitmap> bitmaps = fillPool();
- pool.trimMemory(ComponentCallbacks2.TRIM_MEMORY_COMPLETE);
- for (Bitmap bitmap : bitmaps) {
- assertTrue(bitmap.isRecycled());
- }
- }
-
- public void testClearMemoryCallsRecycleOnRemovedBitmaps() {
- List<Bitmap> bitmaps = fillPool();
- pool.clearMemory();
- for (Bitmap bitmap : bitmaps) {
- assertTrue(bitmap.isRecycled());
- }
- }
-
- public List<Bitmap> fillPool() {
- List<Bitmap> bitmaps = new ArrayList<Bitmap>();
- Bitmap toPut = getBitmap();
- int bitmapSize = getSize(toPut);
- for (int i = 0; i < (SIZE / bitmapSize); i++) {
- bitmaps.add(Bitmap.createBitmap(toPut));
- }
- for (Bitmap bitmap : bitmaps) {
- pool.put(bitmap);
- }
- assertTrue(bitmaps.size() > 0);
- return bitmaps;
- }
-
- private Bitmap getEquivalentFromPool(Bitmap bitmap) {
- return pool.get(bitmap.getWidth(), bitmap.getHeight(), bitmap.getConfig());
- }
-
- private static int getSize(Bitmap bitmap) {
- return bitmap.getRowBytes() * bitmap.getHeight();
- }
-
- private static Bitmap getBitmap() {
- return Bitmap.createBitmap(100, 100, Bitmap.Config.ARGB_8888);
- }
-}
diff --git a/library/tests/src/com/bumptech/glide/resize/bitmap_recycle/AttributeStrategyTest.java b/library/tests/src/com/bumptech/glide/resize/bitmap_recycle/AttributeStrategyTest.java
new file mode 100644
index 00000000..bfba0fd4
--- /dev/null
+++ b/library/tests/src/com/bumptech/glide/resize/bitmap_recycle/AttributeStrategyTest.java
@@ -0,0 +1,87 @@
+package com.bumptech.glide.resize.bitmap_recycle;
+
+import android.graphics.Bitmap;
+import android.test.AndroidTestCase;
+
+public class AttributeStrategyTest extends AndroidTestCase {
+
+ private AttributeStrategy strategy;
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+ strategy = new AttributeStrategy();
+ }
+
+ public void testIGetNullIfNoMatchingBitmapExists() {
+ assertNull(strategy.get(100, 100, Bitmap.Config.ARGB_8888));
+ }
+
+ public void testICanAddAndGetABitmapOfTheSameSizeAndDimensions() {
+ Bitmap bitmap = Bitmap.createBitmap(100, 100, Bitmap.Config.ARGB_8888);
+ strategy.put(bitmap);
+ assertEquals(bitmap, strategy.get(bitmap.getWidth(), bitmap.getHeight(), Bitmap.Config.ARGB_8888));
+ }
+
+ public void testICantGetABitmapOfTheSameDimensionsButDifferentConfigs() {
+ Bitmap bitmap = Bitmap.createBitmap(100, 100, Bitmap.Config.ARGB_8888);
+ strategy.put(bitmap);
+ assertNull(strategy.get(100, 100, Bitmap.Config.RGB_565));
+ }
+
+ public void testICantGetABitmapOfTheSameDimensionsAndSizeButDifferentConfigs() {
+ Bitmap bitmap = Bitmap.createBitmap(100, 100, Bitmap.Config.ARGB_4444);
+ strategy.put(bitmap);
+ assertNull(strategy.get(100, 100, Bitmap.Config.RGB_565));
+ }
+
+ public void testICantGetABitmapOfDifferentWidths() {
+ Bitmap bitmap = Bitmap.createBitmap(100, 100, Bitmap.Config.ARGB_8888);
+ strategy.put(bitmap);
+ assertNull(strategy.get(99, 100, Bitmap.Config.ARGB_8888));
+ }
+
+ public void testICantGetABitmapOfDifferentHeights() {
+ Bitmap bitmap = Bitmap.createBitmap(100, 100, Bitmap.Config.ARGB_8888);
+ strategy.put(bitmap);
+ assertNull(strategy.get(100, 99, Bitmap.Config.ARGB_8888));
+ }
+
+ public void testICantGetABitmapOfDifferentDimensionsButTheSameSize() {
+ Bitmap bitmap = Bitmap.createBitmap(100, 100, Bitmap.Config.ARGB_8888);
+ strategy.put(bitmap);
+ assertNull(strategy.get(50, 200, Bitmap.Config.ARGB_8888));
+ }
+
+ public void testMultipleBitmapsOfDifferentAttributesCanBeAddedAtOnce() {
+ Bitmap first = Bitmap.createBitmap(100, 100, Bitmap.Config.RGB_565);
+ Bitmap second = Bitmap.createBitmap(100, 100, Bitmap.Config.ARGB_8888);
+ Bitmap third = Bitmap.createBitmap(120, 120, Bitmap.Config.RGB_565);
+
+ strategy.put(first);
+ strategy.put(second);
+ strategy.put(third);
+
+ assertEquals(first, strategy.get(100, 100, Bitmap.Config.RGB_565));
+ assertEquals(second, strategy.get(100, 100, Bitmap.Config.ARGB_8888));
+ assertEquals(third, strategy.get(120, 120, Bitmap.Config.RGB_565));
+ }
+
+ public void testLeastRecentlyUsedAttributeSetIsRemovedFirst() {
+ final Bitmap leastRecentlyUsed = Bitmap.createBitmap(100, 100, Bitmap.Config.ALPHA_8);
+ final Bitmap other = Bitmap.createBitmap(1000, 1000, Bitmap.Config.RGB_565);
+ final Bitmap mostRecentlyUsed = Bitmap.createBitmap(100, 100, Bitmap.Config.ARGB_8888);
+
+ strategy.get(100, 100, Bitmap.Config.ALPHA_8);
+ strategy.get(1000, 1000, Bitmap.Config.RGB_565);
+ strategy.get(100, 100, Bitmap.Config.ARGB_8888);
+
+ strategy.put(other);
+ strategy.put(leastRecentlyUsed);
+ strategy.put(mostRecentlyUsed);
+
+ Bitmap removed = strategy.removeLast();
+ assertEquals("Expected=" + strategy.logBitmap(leastRecentlyUsed) + " got=" + strategy.logBitmap(removed),
+ leastRecentlyUsed, removed);
+ }
+}
diff --git a/library/tests/src/com/bumptech/glide/resize/bitmap_recycle/LruBitmapPoolTest.java b/library/tests/src/com/bumptech/glide/resize/bitmap_recycle/LruBitmapPoolTest.java
new file mode 100644
index 00000000..95aa7968
--- /dev/null
+++ b/library/tests/src/com/bumptech/glide/resize/bitmap_recycle/LruBitmapPoolTest.java
@@ -0,0 +1,145 @@
+package com.bumptech.glide.resize.bitmap_recycle;
+
+import android.graphics.Bitmap;
+import android.test.AndroidTestCase;
+
+import java.util.ArrayList;
+import java.util.LinkedList;
+import java.util.List;
+
+import static android.content.ComponentCallbacks2.TRIM_MEMORY_BACKGROUND;
+import static android.content.ComponentCallbacks2.TRIM_MEMORY_COMPLETE;
+import static android.content.ComponentCallbacks2.TRIM_MEMORY_MODERATE;
+
+public class LruBitmapPoolTest extends AndroidTestCase {
+ private static final int MAX_SIZE = 10;
+ private MockStrategy strategy;
+ private LruBitmapPool pool;
+
+ @Override
+ protected void setUp() throws Exception {
+ strategy = new MockStrategy();
+ pool = new LruBitmapPool(MAX_SIZE, strategy);
+ }
+
+ public void testICanAddAndGetABitmap() {
+ fillPool(pool, 1);
+ Bitmap bitmap = Bitmap.createBitmap(100, 100, Bitmap.Config.ARGB_8888);
+ pool.put(bitmap);
+ assertNotNull(pool.get(100, 100, Bitmap.Config.ARGB_8888));
+ }
+
+ public void testImmutableBitmapsAreNotAdded() {
+ pool.put(Bitmap.createBitmap(100, 100, Bitmap.Config.ARGB_8888).copy(Bitmap.Config.ARGB_8888, false));
+ assertEquals(0, strategy.bitmaps.size());
+ }
+
+ public void testItIsSizeLimited() {
+ fillPool(pool, MAX_SIZE + 2);
+ assertEquals(2, strategy.numRemoves);
+ }
+
+ public void testBitmapLargerThanPoolIsNotAdded() {
+ strategy = new MockStrategy() {
+ @Override
+ public int getSize(Bitmap bitmap) {
+ return 4;
+ }
+ };
+ pool = new LruBitmapPool(3, strategy);
+ pool.put(Bitmap.createBitmap(100, 100, Bitmap.Config.ARGB_8888));
+ assertEquals(0, strategy.numRemoves);
+ assertEquals(0, strategy.numPuts);
+ }
+
+ public void testClearMemoryRemovesAllBitmaps() {
+ fillPool(pool, MAX_SIZE);
+ pool.clearMemory();
+
+ assertEquals(MAX_SIZE, strategy.numRemoves);
+ }
+
+ public void testEvictedBitmapsAreRecycled() {
+ fillPool(pool, MAX_SIZE);
+ List<Bitmap> bitmaps = new ArrayList<Bitmap>(MAX_SIZE);
+ for (Bitmap b : strategy.bitmaps) {
+ bitmaps.add(b);
+ }
+
+ pool.clearMemory();
+
+ for (Bitmap b : bitmaps) {
+ assertTrue(b.isRecycled());
+ }
+ }
+
+ public void testTrimMemoryBackgroundOrLessRemovesHalfOfBitmaps() {
+ testTrimMemory(MAX_SIZE, TRIM_MEMORY_BACKGROUND, MAX_SIZE / 2);
+ }
+
+ public void testTrimMemoryBackgroundOrLessRemovesNoBitmapsIfPoolLessThanHalfFull() {
+ testTrimMemory(MAX_SIZE / 2, TRIM_MEMORY_BACKGROUND, 0);
+ }
+
+ public void testTrimMemoryModerateOrGreaterRemovesAllBitmaps() {
+ for (int trimLevel : new int[] { TRIM_MEMORY_MODERATE, TRIM_MEMORY_COMPLETE }) {
+ testTrimMemory(MAX_SIZE, trimLevel, MAX_SIZE);
+ }
+ }
+
+ private void testTrimMemory(int fillSize, int trimLevel, int expectedSize) {
+ MockStrategy strategy = new MockStrategy();
+ LruBitmapPool pool = new LruBitmapPool(MAX_SIZE, strategy);
+ fillPool(pool, fillSize);
+ pool.trimMemory(trimLevel);
+ assertEquals("Failed level=" + trimLevel, expectedSize, strategy.numRemoves);
+ }
+
+ private void fillPool(LruBitmapPool pool, int fillCount) {
+ for (int i = 0; i < fillCount; i++) {
+ pool.put(Bitmap.createBitmap(100, 100, Bitmap.Config.ARGB_8888));
+ }
+ }
+
+ private static final int getSize(Bitmap bitmap) {
+ return bitmap.getRowBytes() * bitmap.getHeight();
+ }
+
+ private static class MockStrategy implements LruPoolStrategy {
+ private LinkedList<Bitmap> bitmaps = new LinkedList<Bitmap>();
+ 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.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;
+ }
+ }
+}
diff --git a/library/tests/src/com/bumptech/glide/resize/bitmap_recycle/SizeStrategyTest.java b/library/tests/src/com/bumptech/glide/resize/bitmap_recycle/SizeStrategyTest.java
new file mode 100644
index 00000000..bc24710f
--- /dev/null
+++ b/library/tests/src/com/bumptech/glide/resize/bitmap_recycle/SizeStrategyTest.java
@@ -0,0 +1,105 @@
+package com.bumptech.glide.resize.bitmap_recycle;
+
+import android.graphics.Bitmap;
+import android.test.AndroidTestCase;
+
+public class SizeStrategyTest extends AndroidTestCase {
+ private SizeStrategy strategy;
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+ strategy = new SizeStrategy();
+ }
+
+ public void testIGetNullIfNoMatchingBitmapExists() {
+ assertNull(strategy.get(100, 100, Bitmap.Config.ARGB_8888));
+ }
+
+ public void testICanAddAndGetABitmapOfTheSameSizeAndDimensions() {
+ Bitmap bitmap = Bitmap.createBitmap(100, 100, Bitmap.Config.ARGB_8888);
+ strategy.put(bitmap);
+ assertEquals(bitmap, strategy.get(bitmap.getWidth(), bitmap.getHeight(), Bitmap.Config.ARGB_8888));
+ }
+
+ public void testICanAddAndGetABitmapOfDifferentConfigsButSameSize() {
+ Bitmap original = Bitmap.createBitmap(400, 400, Bitmap.Config.ARGB_8888);
+ strategy.put(original);
+ assertEquals(original, strategy.get(800, 400, Bitmap.Config.RGB_565));
+ }
+
+ public void testICanAddAndGetABitmapOfDifferentDimensionsButSameSize() {
+ Bitmap original = Bitmap.createBitmap(400, 400, Bitmap.Config.ARGB_8888);
+ strategy.put(original);
+ assertEquals(original, strategy.get(200, 800, Bitmap.Config.ARGB_8888));
+ }
+
+ public void testICanGetABitmapUpToFourTimesLarger() {
+ Bitmap original = Bitmap.createBitmap(400, 400, Bitmap.Config.ARGB_8888);
+ strategy.put(original);
+ assertEquals(original, strategy.get(200, 200, Bitmap.Config.ARGB_8888));
+ }
+
+ public void testICantGetABitmapMoreThanFourTimesLarger() {
+ Bitmap original = Bitmap.createBitmap(401, 401, Bitmap.Config.ARGB_8888);
+ strategy.put(original);
+ assertNull(strategy.get(200, 200, Bitmap.Config.ARGB_8888));
+ }
+
+ public void testICantGetASmallerBitmap() {
+ Bitmap original = Bitmap.createBitmap(99, 99, Bitmap.Config.ARGB_8888);
+ strategy.put(original);
+ assertNull(strategy.get(100, 100, Bitmap.Config.ARGB_8888));
+ }
+
+ public void testReturnedDimensionsMatchIfSizeDoesNotMatch() {
+ Bitmap original = Bitmap.createBitmap(100, 100, Bitmap.Config.ARGB_8888);
+ strategy.put(original);
+ Bitmap result = strategy.get(99, 99, Bitmap.Config.ARGB_8888);
+ assertEquals(99, result.getWidth());
+ assertEquals(99, result.getHeight());
+ }
+
+ public void testReturnedConfigMatchesIfSizeDoesNotMatch() {
+ Bitmap original = Bitmap.createBitmap(100, 100, Bitmap.Config.ARGB_8888);
+ strategy.put(original);
+ Bitmap result = strategy.get(100, 100, Bitmap.Config.RGB_565);
+ assertEquals(Bitmap.Config.RGB_565, result.getConfig());
+ }
+
+ public void testSmallestMatchingSizeIsReturned() {
+ Bitmap smallest = Bitmap.createBitmap(100, 100, Bitmap.Config.ARGB_8888);
+ Bitmap medium = Bitmap.createBitmap(120, 120, Bitmap.Config.ARGB_8888);
+ Bitmap large = Bitmap.createBitmap(150, 150, Bitmap.Config.ARGB_8888);
+
+ strategy.put(large);
+ strategy.put(smallest);
+ strategy.put(medium);
+
+ assertEquals(smallest, strategy.get(99, 99, Bitmap.Config.ARGB_8888));
+ }
+
+ // This ensures that our sizes are incremented and decremented appropriately so we don't think we have more bitmaps
+ // of a size than we actually do.
+ public void testAMatchingBitmapIsReturnedIfAvailable() {
+ strategy.put(Bitmap.createBitmap(100, 100, Bitmap.Config.ARGB_8888));
+ strategy.get(99, 99, Bitmap.Config.ARGB_8888);
+ strategy.put(Bitmap.createBitmap(101, 101, Bitmap.Config.ARGB_8888));
+ assertNotNull(strategy.get(99, 99, Bitmap.Config.ARGB_8888));
+ }
+
+ public void testLeastRecentlyObtainedSizeIsRemovedFirst() {
+ Bitmap mostRecentlyUsed = Bitmap.createBitmap(100, 100, Bitmap.Config.ARGB_8888);
+ Bitmap other = Bitmap.createBitmap(1000, 1000, Bitmap.Config.RGB_565);
+ Bitmap leastRecentlyUsed = Bitmap.createBitmap(500, 500, Bitmap.Config.ARGB_8888);
+ strategy.get(500, 500, Bitmap.Config.ARGB_8888);
+ strategy.get(1000, 1000, Bitmap.Config.RGB_565);
+ strategy.get(100, 100, Bitmap.Config.ARGB_8888);
+
+ strategy.put(other);
+ strategy.put(leastRecentlyUsed);
+ strategy.put(mostRecentlyUsed);
+
+ assertEquals(leastRecentlyUsed, strategy.removeLast());
+ }
+}