Permalink
Browse files

Add new RecyclePolicy. Allows you to customise the policy in which re…

…cycle() is called.
  • Loading branch information...
1 parent 2ca078d commit 0b513f56be8acd04175ef1e7bfaae8b66084e775 @chrisbanes committed Feb 2, 2013
View
94 library/src/uk/co/senab/bitmapcache/BitmapLruCache.java
@@ -27,6 +27,7 @@
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.AsyncTask;
+import android.os.Build;
import android.os.Looper;
import android.os.Process;
import android.util.Log;
@@ -48,25 +49,59 @@
* <p>
* Clients can call {@link #get(String)} to retrieve a cached value from the
* given Url. This will check all available caches for the value. There are also
- * the {@link #getFromDiskCache(String)} and {@link #getFromMemoryCache(String)}
+ * the {@link #getFromDiskCache(String, android.graphics.BitmapFactory.Options)} and {@link #getFromMemoryCache(String)}
* which allow more granular access.
* </p>
*
* <p>
* There are a number of update methods. {@link #put(String, InputStream)} and
- * {@link #put(String, InputStream, boolean)} are the preferred versions of the
+ * {@link #put(String, InputStream)} are the preferred versions of the
* method, as they allow 1:1 caching to disk of the original content. <br />
- * {@link #put(String, Bitmap)} and {@link #put(String, Bitmap, boolean)} should
- * only be used if you can't get access to the original InputStream.
+ * {@link #put(String, Bitmap)}} should only be used if you can't get access to the original InputStream.
* </p>
*
* @author Chris Banes
*/
public class BitmapLruCache {
- // The number of seconds after the last edit that the Disk Cache should be
- // flushed
- static final int DISK_CACHE_FLUSH_DELAY_SECS = 5;
+ /**
+ * The recycle policy controls if the {@link android.graphics.Bitmap#recycle()} is automatically called, when it is
+ * no longer being used. To set this, use the
+ * {@link Builder#setMemoryCacheRecyclePolicy(uk.co.senab.bitmapcache.BitmapLruCache.RecyclePolicy) Builder.setMemoryCacheRecyclePolicy()} method.
+ */
+ public static enum RecyclePolicy {
+ /**
+ * The Bitmap is never recycled automatically.
+ */
+ DISABLED,
+
+ /**
+ * The Bitmap is only automatically recycled if running on a device API v10 or earlier.
+ */
+ PRE_HONEYCOMB_ONLY,
+
+ /**
+ * The Bitmap is always recycled when no longer being used. This is the default.
+ */
+ ALWAYS;
+
+ boolean canRecycle() {
+ switch (this) {
+ case DISABLED:
+ return false;
+ case PRE_HONEYCOMB_ONLY:
+ return Build.VERSION.SDK_INT < Build.VERSION_CODES.HONEYCOMB;
+ case ALWAYS:
+ return true;
+ }
+
+ return false;
+ }
+ }
+
+ // The number of seconds after the last edit that the Disk Cache should be
+ // flushed
+ static final int DISK_CACHE_FLUSH_DELAY_SECS = 5;
/**
* @throws IllegalStateException if the calling thread is the main/UI
@@ -94,6 +129,8 @@ private static String transformUrlForDiskCacheKey(String url) {
private DiskLruCache mDiskCache;
private BitmapMemoryLruCache mMemoryCache;
+ private final RecyclePolicy mRecyclePolicy;
+
// Variables which are only used when the Disk Cache is enabled
private HashMap<String, ReentrantLock> mDiskCacheEditLocks;
private ScheduledThreadPoolExecutor mDiskCacheFlusherExecutor;
@@ -102,8 +139,9 @@ private static String transformUrlForDiskCacheKey(String url) {
// Transient
private ScheduledFuture<?> mDiskCacheFuture;
- protected BitmapLruCache(BitmapMemoryLruCache memoryCache) {
+ protected BitmapLruCache(BitmapMemoryLruCache memoryCache, RecyclePolicy recyclePolicy) {
mMemoryCache = memoryCache;
+ mRecyclePolicy = recyclePolicy;
}
/**
@@ -221,7 +259,7 @@ public CacheableBitmapDrawable getFromDiskCache(final String url, final BitmapFa
Bitmap bitmap = BitmapFactory.decodeStream(snapshot.getInputStream(0), null, decodeOpts);
if (null != bitmap) {
- result = new CacheableBitmapDrawable(url, bitmap);
+ result = new CacheableBitmapDrawable(url, bitmap, mRecyclePolicy);
mMemoryCache.put(result);
} else {
// If we get here, the file in the cache can't be
@@ -279,7 +317,7 @@ public CacheableBitmapDrawable getFromMemoryCache(final String url) {
* @return CacheableBitmapDrawable which can be used to display the bitmap.
*/
public CacheableBitmapDrawable put(final String url, final Bitmap bitmap) {
- CacheableBitmapDrawable d = new CacheableBitmapDrawable(url, bitmap);
+ CacheableBitmapDrawable d = new CacheableBitmapDrawable(url, bitmap, mRecyclePolicy);
if (null != mMemoryCache) {
mMemoryCache.put(d);
@@ -384,7 +422,7 @@ public CacheableBitmapDrawable put(final String url, final InputStream inputStre
Bitmap bitmap = BitmapFactory.decodeFile(tmpFile.getAbsolutePath(), decodeOpts);
if (null != bitmap) {
- d = new CacheableBitmapDrawable(url, bitmap);
+ d = new CacheableBitmapDrawable(url, bitmap, mRecyclePolicy);
if (null != mMemoryCache) {
d.setCached(true);
@@ -504,6 +542,8 @@ private void scheduleDiskCacheFlush() {
static final int DEFAULT_DISK_CACHE_MAX_SIZE_MB = 10;
static final int DEFAULT_MEM_CACHE_MAX_SIZE_MB = 3;
+ static final RecyclePolicy DEFAULT_RECYCLE_POLICY = RecyclePolicy.ALWAYS;
+
// Only used for Javadoc
static final float DEFAULT_MEMORY_CACHE_HEAP_PERCENTAGE = DEFAULT_MEMORY_CACHE_HEAP_RATIO * 100;
static final float MAX_MEMORY_CACHE_HEAP_PERCENTAGE = MAX_MEMORY_CACHE_HEAP_RATIO * 100;
@@ -518,6 +558,7 @@ private static long getHeapSize() {
private boolean mMemoryCacheEnabled;
private int mMemoryCacheMaxSize;
+ private RecyclePolicy mMemoryRecyclePolicy;
public Builder() {
// Disk Cache is disabled by default, but it's default size is set
@@ -526,6 +567,7 @@ public Builder() {
// Memory Cache is enabled by default, with a small maximum size
mMemoryCacheEnabled = true;
mMemoryCacheMaxSize = DEFAULT_MEM_CACHE_MAX_SIZE_MB * MEGABYTE;
+ mMemoryRecyclePolicy = DEFAULT_RECYCLE_POLICY;
}
/**
@@ -542,7 +584,7 @@ public BitmapLruCache build() {
memoryCache = new BitmapMemoryLruCache(mMemoryCacheMaxSize);
}
- final BitmapLruCache cache = new BitmapLruCache(memoryCache);
+ final BitmapLruCache cache = new BitmapLruCache(memoryCache, mMemoryRecyclePolicy);
if (isValidOptionsForDiskCache()) {
new AsyncTask<Void, Void, DiskLruCache>() {
@@ -630,8 +672,9 @@ public Builder setMemoryCacheMaxSize(int size) {
/**
* Sets the Memory Cache maximum size to be the default value of
* {@value #DEFAULT_MEMORY_CACHE_HEAP_PERCENTAGE}% of heap size.
- *
- * @param context - Context, needed to retrieve heap size.
+ *
+ * @return This Builder object to allow for chaining of calls to set
+ * methods.
*/
public Builder setMemoryCacheMaxSizeUsingHeapSize() {
return setMemoryCacheMaxSizeUsingHeapSize(DEFAULT_MEMORY_CACHE_HEAP_RATIO);
@@ -641,16 +684,35 @@ public Builder setMemoryCacheMaxSizeUsingHeapSize() {
* Sets the Memory Cache maximum size to be the given percentage of heap
* size. This is capped at {@value #MAX_MEMORY_CACHE_HEAP_PERCENTAGE}%
* of the app heap size.
- *
- * @param context - Context, needed to retrieve heap size.
+ *
* @param percentageOfHeap - percentage of heap size. Valid values are
* 0.0 <= x <= {@value #MAX_MEMORY_CACHE_HEAP_RATIO}.
+ *
+ * @return This Builder object to allow for chaining of calls to set
+ * methods.
*/
public Builder setMemoryCacheMaxSizeUsingHeapSize(float percentageOfHeap) {
int size = (int) Math.round(getHeapSize() * Math.min(percentageOfHeap, MAX_MEMORY_CACHE_HEAP_RATIO));
return setMemoryCacheMaxSize(size);
}
+ /**
+ * Sets the recycle policy for the memory cache. This controls if/when {@link android.graphics.Bitmap#recycle()}
+ * is called.
+ *
+ * @param recyclePolicy - New recycle policy, can not be null.
+ * @return This Builder object to allow for chaining of calls to set
+ * methods.
+ */
+ public Builder setMemoryCacheRecyclePolicy(RecyclePolicy recyclePolicy) {
+ if (null == recyclePolicy) {
+ throw new IllegalArgumentException("The recycle policy can not be null");
+ }
+
+ mMemoryRecyclePolicy = recyclePolicy;
+ return this;
+ }
+
private boolean isValidOptionsForDiskCache() {
if (mDiskCacheEnabled) {
if (null == mDiskCacheLocation) {
View
15 library/src/uk/co/senab/bitmapcache/CacheableBitmapDrawable.java
@@ -25,8 +25,11 @@
static final String LOG_TAG = "CacheableBitmapDrawable";
+ // URL Associated with this Bitmap
private final String mUrl;
+ private final BitmapLruCache.RecyclePolicy mRecyclePolicy;
+
// Number of Views currently displaying bitmap
private int mDisplayingCount;
@@ -42,15 +45,12 @@
// Handler which may be used later
private static final Handler sHandler = new Handler(Looper.getMainLooper());
- public CacheableBitmapDrawable(Bitmap bitmap) {
- this(null, bitmap);
- }
-
@SuppressWarnings("deprecation")
- public CacheableBitmapDrawable(String url, Bitmap bitmap) {
+ CacheableBitmapDrawable(String url, Bitmap bitmap, BitmapLruCache.RecyclePolicy recyclePolicy) {
super(bitmap);
mUrl = url;
+ mRecyclePolicy = recyclePolicy;
mDisplayingCount = 0;
mCacheCount = 0;
}
@@ -179,6 +179,11 @@ private synchronized void checkState(final boolean ignoreBeenDisplayed) {
mHasBeenDisplayed, mDisplayingCount, mCacheCount, mUrl));
}
+ // If the policy doesn't let us recycle, return now
+ if (!mRecyclePolicy.canRecycle()) {
+ return;
+ }
+
if (mCacheCount <= 0 && mDisplayingCount <= 0) {
// We're not being referenced or used anywhere

0 comments on commit 0b513f5

Please sign in to comment.