aboutsummaryrefslogtreecommitdiff
path: root/src/main/java/com
diff options
context:
space:
mode:
authorAnonymous <no-reply@google.com>2018-10-11 11:02:44 -0700
committerJeff Davidson <jpd@google.com>2018-10-11 11:50:43 -0700
commitd998d6e2d201bd26bab6f7624ccfa2242b58a05e (patch)
tree26a0438ea15ce7651d1c54cb99f13e2d8d1951dd /src/main/java/com
parentc409124cab8fa87dab8a3e42ce34844f5a4fa7ea (diff)
downloadvolley-d998d6e2d201bd26bab6f7624ccfa2242b58a05e.tar.gz
- 321174452380acd5caa7c19aac99cb95a2ed0ff6 Add a default image bitmap and an error image bitmap. (#2... by Ammar Aijazi <aaijazi@users.noreply.github.com> - cb5d331761c4785b325acc7ff5caf8f41e932c69 Bump Volley to 1.2.0-SNAPSHOT. by Jeff Davidson <jpd@google.com> - c31351334868a17cb79ab5b067d798bc80e343a3 Fix the build. by Jeff Davidson <jpd@google.com> - 99d8ed84ddf653cb5f61a9ad63e5a3ced799d9ce Reduce cache churn from large entries. by Jeff Davidson <jpd@google.com> - 6b7b3a2df79506269a0730a095849c5a87fc9cbb Enforce disk size limit more strictly in DiskBasedCache. by Jeff Davidson <jpd@google.com> - 64481a321b9e57c78f22c7df53732e03f530933a Don't drop batched responses when new requests complete. ... by Jeff Davidson <jpd236@cornell.edu> - 4e60e9d2ac2f2c81661a7f0d1bcbc72c190059c2 Bump version to 1.1.2 after final 1.1.1 release by Jeff Davidson <jpd@google.com> - d1a3d5388c79ff1a6fdb904daeff9b39d0bb7d26 Delete Android.mk (#204) by Jeff Davidson <jpd236@cornell.edu> GitOrigin-RevId: 321174452380acd5caa7c19aac99cb95a2ed0ff6 Change-Id: I433459689ad2fe1bf40e8ff30d196d948ef73f81
Diffstat (limited to 'src/main/java/com')
-rw-r--r--src/main/java/com/android/volley/toolbox/DiskBasedCache.java50
-rw-r--r--src/main/java/com/android/volley/toolbox/ImageLoader.java5
-rw-r--r--src/main/java/com/android/volley/toolbox/NetworkImageView.java72
3 files changed, 102 insertions, 25 deletions
diff --git a/src/main/java/com/android/volley/toolbox/DiskBasedCache.java b/src/main/java/com/android/volley/toolbox/DiskBasedCache.java
index c49588f..75c217f 100644
--- a/src/main/java/com/android/volley/toolbox/DiskBasedCache.java
+++ b/src/main/java/com/android/volley/toolbox/DiskBasedCache.java
@@ -65,7 +65,7 @@ public class DiskBasedCache implements Cache {
private static final int DEFAULT_DISK_USAGE_BYTES = 5 * 1024 * 1024;
/** High water mark percentage for the cache */
- private static final float HYSTERESIS_FACTOR = 0.9f;
+ @VisibleForTesting static final float HYSTERESIS_FACTOR = 0.9f;
/** Magic number for current version of cache file format. */
private static final int CACHE_MAGIC = 0x20150306;
@@ -74,7 +74,9 @@ public class DiskBasedCache implements Cache {
* Constructs an instance of the DiskBasedCache at the specified directory.
*
* @param rootDirectory The root directory of the cache.
- * @param maxCacheSizeInBytes The maximum size of the cache in bytes.
+ * @param maxCacheSizeInBytes The maximum size of the cache in bytes. Note that the cache may
+ * briefly exceed this size on disk when writing a new entry that pushes it over the limit
+ * until the ensuing pruning completes.
*/
public DiskBasedCache(File rootDirectory, int maxCacheSizeInBytes) {
mRootDirectory = rootDirectory;
@@ -166,8 +168,6 @@ public class DiskBasedCache implements Cache {
new BufferedInputStream(createInputStream(file)), entrySize);
try {
CacheHeader entry = CacheHeader.readHeader(cis);
- // NOTE: When this entry was put, its size was recorded as data.length, but
- // when the entry is initialized below, its size is recorded as file.length()
entry.size = entrySize;
putEntry(entry.key, entry);
} finally {
@@ -203,7 +203,14 @@ public class DiskBasedCache implements Cache {
/** Puts the entry with the specified key into the cache. */
@Override
public synchronized void put(String key, Entry entry) {
- pruneIfNeeded(entry.data.length);
+ // If adding this entry would trigger a prune, but pruning would cause the new entry to be
+ // deleted, then skip writing the entry in the first place, as this is just churn.
+ // Note that we don't include the cache header overhead in this calculation for simplicity,
+ // so putting entries which are just below the threshold may still cause this churn.
+ if (mTotalSize + entry.data.length > mMaxCacheSizeInBytes
+ && entry.data.length > mMaxCacheSizeInBytes * HYSTERESIS_FACTOR) {
+ return;
+ }
File file = getFileForKey(key);
try {
BufferedOutputStream fos = new BufferedOutputStream(createOutputStream(file));
@@ -216,7 +223,9 @@ public class DiskBasedCache implements Cache {
}
fos.write(entry.data);
fos.close();
+ e.size = file.length();
putEntry(key, e);
+ pruneIfNeeded();
return;
} catch (IOException e) {
}
@@ -256,13 +265,9 @@ public class DiskBasedCache implements Cache {
return new File(mRootDirectory, getFilenameForKey(key));
}
- /**
- * Prunes the cache to fit the amount of bytes specified.
- *
- * @param neededSpace The amount of bytes we are trying to fit into the cache.
- */
- private void pruneIfNeeded(int neededSpace) {
- if ((mTotalSize + neededSpace) < mMaxCacheSizeInBytes) {
+ /** Prunes the cache to fit the maximum size. */
+ private void pruneIfNeeded() {
+ if (mTotalSize < mMaxCacheSizeInBytes) {
return;
}
if (VolleyLog.DEBUG) {
@@ -288,7 +293,7 @@ public class DiskBasedCache implements Cache {
iterator.remove();
prunedFiles++;
- if ((mTotalSize + neededSpace) < mMaxCacheSizeInBytes * HYSTERESIS_FACTOR) {
+ if (mTotalSize < mMaxCacheSizeInBytes * HYSTERESIS_FACTOR) {
break;
}
}
@@ -331,7 +336,7 @@ public class DiskBasedCache implements Cache {
* @param length number of bytes to read
* @throws IOException if fails to read all bytes
*/
- // VisibleForTesting
+ @VisibleForTesting
static byte[] streamToBytes(CountingInputStream cis, long length) throws IOException {
long maxLength = cis.bytesRemaining();
// Length cannot be negative or greater than bytes remaining, and must not overflow int.
@@ -343,20 +348,26 @@ public class DiskBasedCache implements Cache {
return bytes;
}
- // VisibleForTesting
+ @VisibleForTesting
InputStream createInputStream(File file) throws FileNotFoundException {
return new FileInputStream(file);
}
- // VisibleForTesting
+ @VisibleForTesting
OutputStream createOutputStream(File file) throws FileNotFoundException {
return new FileOutputStream(file);
}
/** Handles holding onto the cache headers for an entry. */
- // VisibleForTesting
+ @VisibleForTesting
static class CacheHeader {
- /** The size of the data identified by this CacheHeader. (This is not serialized to disk. */
+ /**
+ * The size of the data identified by this CacheHeader on disk (both header and data).
+ *
+ * <p>Must be set by the caller after it has been calculated.
+ *
+ * <p>This is not serialized to disk.
+ */
long size;
/** The key that identifies the cache entry. */
@@ -389,7 +400,7 @@ public class DiskBasedCache implements Cache {
long softTtl,
List<Header> allResponseHeaders) {
this.key = key;
- this.etag = ("".equals(etag)) ? null : etag;
+ this.etag = "".equals(etag) ? null : etag;
this.serverDate = serverDate;
this.lastModified = lastModified;
this.ttl = ttl;
@@ -412,7 +423,6 @@ public class DiskBasedCache implements Cache {
entry.ttl,
entry.softTtl,
getAllResponseHeaders(entry));
- size = entry.data.length;
}
private static List<Header> getAllResponseHeaders(Entry entry) {
diff --git a/src/main/java/com/android/volley/toolbox/ImageLoader.java b/src/main/java/com/android/volley/toolbox/ImageLoader.java
index 076c212..270935f 100644
--- a/src/main/java/com/android/volley/toolbox/ImageLoader.java
+++ b/src/main/java/com/android/volley/toolbox/ImageLoader.java
@@ -239,8 +239,11 @@ public class ImageLoader {
// Update the caller to let them know that they should use the default bitmap.
imageListener.onResponse(imageContainer, true);
- // Check to see if a request is already in-flight.
+ // Check to see if a request is already in-flight or completed but pending batch delivery.
BatchedImageRequest request = mInFlightRequests.get(cacheKey);
+ if (request == null) {
+ request = mBatchedResponses.get(cacheKey);
+ }
if (request != null) {
// If it is, add this request to the list of listeners.
request.addContainer(imageContainer);
diff --git a/src/main/java/com/android/volley/toolbox/NetworkImageView.java b/src/main/java/com/android/volley/toolbox/NetworkImageView.java
index a490a79..6ad1e49 100644
--- a/src/main/java/com/android/volley/toolbox/NetworkImageView.java
+++ b/src/main/java/com/android/volley/toolbox/NetworkImageView.java
@@ -14,7 +14,9 @@
package com.android.volley.toolbox;
import android.content.Context;
+import android.graphics.Bitmap;
import android.support.annotation.MainThread;
+import android.support.annotation.Nullable;
import android.text.TextUtils;
import android.util.AttributeSet;
import android.view.ViewGroup.LayoutParams;
@@ -28,12 +30,30 @@ public class NetworkImageView extends ImageView {
/** The URL of the network image to load */
private String mUrl;
- /** Resource ID of the image to be used as a placeholder until the network image is loaded. */
+ /**
+ * Resource ID of the image to be used as a placeholder until the network image is loaded. Won't
+ * be set at the same time as mDefaultImageBitmap.
+ */
private int mDefaultImageId;
- /** Resource ID of the image to be used if the network response fails. */
+ /**
+ * Bitmap of the image to be used as a placeholder until the network image is loaded. Won't be
+ * set at the same time as mDefaultImageId.
+ */
+ @Nullable Bitmap mDefaultImageBitmap;
+
+ /**
+ * Resource ID of the image to be used if the network response fails. Won't be set at the same
+ * time as mErrorImageBitmap.
+ */
private int mErrorImageId;
+ /**
+ * Bitmap of the image to be used if the network response fails. Won't be set at the same time
+ * as mErrorImageId.
+ */
+ @Nullable private Bitmap mErrorImageBitmap;
+
/** Local copy of the ImageLoader. */
private ImageLoader mImageLoader;
@@ -57,8 +77,10 @@ public class NetworkImageView extends ImageView {
* immediately either set the cached image (if available) or the default image specified by
* {@link NetworkImageView#setDefaultImageResId(int)} on the view.
*
- * <p>NOTE: If applicable, {@link NetworkImageView#setDefaultImageResId(int)} and {@link
- * NetworkImageView#setErrorImageResId(int)} should be called prior to calling this function.
+ * <p>NOTE: If applicable, {@link NetworkImageView#setDefaultImageResId(int)} or {@link
+ * NetworkImageView#setDefaultImageBitmap} and {@link NetworkImageView#setErrorImageResId(int)}
+ * or {@link NetworkImageView#setErrorImageBitmap(Bitmap)} should be called prior to calling
+ * this function.
*
* <p>Must be called from the main thread.
*
@@ -77,20 +99,56 @@ public class NetworkImageView extends ImageView {
/**
* Sets the default image resource ID to be used for this view until the attempt to load it
* completes.
+ *
+ * <p>Cannot be called with {@link NetworkImageView#setDefaultImageBitmap}.
*/
public void setDefaultImageResId(int defaultImage) {
+ if (mDefaultImageBitmap != null) {
+ throw new IllegalArgumentException("Can't have a default image resource ID and bitmap");
+ }
mDefaultImageId = defaultImage;
}
/**
+ * Sets the default image bitmap to be used for this view until the attempt to load it
+ * completes.
+ *
+ * <p>Cannot be called with {@link NetworkImageView#setDefaultImageResId}.
+ */
+ public void setDefaultImageBitmap(Bitmap defaultImage) {
+ if (mDefaultImageId != 0) {
+ throw new IllegalArgumentException("Can't have a default image resource ID and bitmap");
+ }
+ mDefaultImageBitmap = defaultImage;
+ }
+
+ /**
* Sets the error image resource ID to be used for this view in the event that the image
* requested fails to load.
+ *
+ * <p>Cannot be called with {@link NetworkImageView#setErrorImageBitmap}.
*/
public void setErrorImageResId(int errorImage) {
+ if (mErrorImageBitmap != null) {
+ throw new IllegalArgumentException("Can't have an error image resource ID and bitmap");
+ }
mErrorImageId = errorImage;
}
/**
+ * Sets the error image bitmap to be used for this view in the event that the image requested
+ * fails to load.
+ *
+ * <p>Cannot be called with {@link NetworkImageView#setErrorImageResId}.
+ */
+ public void setErrorImageBitmap(Bitmap errorImage) {
+ if (mErrorImageId != 0) {
+ throw new IllegalArgumentException("Can't have an error image resource ID and bitmap");
+ }
+ mErrorImageBitmap = errorImage;
+ }
+
+ /**
* Loads the image for the view if it isn't already loaded.
*
* @param isInLayoutPass True if this was invoked from a layout pass, false otherwise.
@@ -152,6 +210,8 @@ public class NetworkImageView extends ImageView {
public void onErrorResponse(VolleyError error) {
if (mErrorImageId != 0) {
setImageResource(mErrorImageId);
+ } else if (mErrorImageBitmap != null) {
+ setImageBitmap(mErrorImageBitmap);
}
}
@@ -180,6 +240,8 @@ public class NetworkImageView extends ImageView {
setImageBitmap(response.getBitmap());
} else if (mDefaultImageId != 0) {
setImageResource(mDefaultImageId);
+ } else if (mDefaultImageBitmap != null) {
+ setImageBitmap(mDefaultImageBitmap);
}
}
},
@@ -191,6 +253,8 @@ public class NetworkImageView extends ImageView {
private void setDefaultImageOrNull() {
if (mDefaultImageId != 0) {
setImageResource(mDefaultImageId);
+ } else if (mDefaultImageBitmap != null) {
+ setImageBitmap(mDefaultImageBitmap);
} else {
setImageBitmap(null);
}