aboutsummaryrefslogtreecommitdiff
path: root/library/src/main/java/com
diff options
context:
space:
mode:
authorSam Judd <judds@google.com>2014-11-03 18:46:27 -0800
committerSam Judd <judds@google.com>2014-11-04 07:24:06 -0800
commit2007440c380df454db15f83b019a5b4c55ca4b72 (patch)
treec86d5e35750d55a05a8e718c11cf0c7d0c7740dd /library/src/main/java/com
parent17180f4ce97118d61e609fef1ebbcbaebdb1d19e (diff)
downloadglide-2007440c380df454db15f83b019a5b4c55ca4b72.tar.gz
Add API to fix mark limit/buffer size.
Fixes #225.
Diffstat (limited to 'library/src/main/java/com')
-rw-r--r--library/src/main/java/com/bumptech/glide/load/engine/bitmap_recycle/LruBitmapPool.java4
-rw-r--r--library/src/main/java/com/bumptech/glide/load/resource/bitmap/Downsampler.java20
-rw-r--r--library/src/main/java/com/bumptech/glide/load/resource/bitmap/RecyclableBufferedInputStream.java27
-rw-r--r--library/src/main/java/com/bumptech/glide/util/ExceptionCatchingInputStream.java12
4 files changed, 48 insertions, 15 deletions
diff --git a/library/src/main/java/com/bumptech/glide/load/engine/bitmap_recycle/LruBitmapPool.java b/library/src/main/java/com/bumptech/glide/load/engine/bitmap_recycle/LruBitmapPool.java
index 8c5947bd..79d8c6c4 100644
--- a/library/src/main/java/com/bumptech/glide/load/engine/bitmap_recycle/LruBitmapPool.java
+++ b/library/src/main/java/com/bumptech/glide/load/engine/bitmap_recycle/LruBitmapPool.java
@@ -63,6 +63,10 @@ public class LruBitmapPool implements BitmapPool {
@Override
public synchronized boolean put(Bitmap bitmap) {
if (!bitmap.isMutable() || strategy.getSize(bitmap) > maxSize) {
+ if (Log.isLoggable(TAG, Log.VERBOSE)) {
+ Log.v(TAG, "Reject bitmap from pool=" + strategy.logBitmap(bitmap) + " is mutable="
+ + bitmap.isMutable());
+ }
return false;
}
diff --git a/library/src/main/java/com/bumptech/glide/load/resource/bitmap/Downsampler.java b/library/src/main/java/com/bumptech/glide/load/resource/bitmap/Downsampler.java
index f5e17e95..904a7c45 100644
--- a/library/src/main/java/com/bumptech/glide/load/resource/bitmap/Downsampler.java
+++ b/library/src/main/java/com/bumptech/glide/load/resource/bitmap/Downsampler.java
@@ -105,6 +105,7 @@ public abstract class Downsampler implements BitmapDecoder<InputStream> {
final byte[] bytesForOptions = byteArrayPool.getBytes();
final byte[] bytesForStream = byteArrayPool.getBytes();
final BitmapFactory.Options options = getDefaultOptions();
+
// TODO(#126): when the framework handles exceptions better, consider removing.
final ExceptionCatchingInputStream stream =
ExceptionCatchingInputStream.obtain(new RecyclableBufferedInputStream(is, bytesForStream));
@@ -137,9 +138,10 @@ public abstract class Downsampler implements BitmapDecoder<InputStream> {
final int sampleSize = getRoundedSampleSize(degreesToRotate, inWidth, inHeight, outWidth, outHeight);
final Bitmap downsampled =
- downsampleWithSize(stream, options, pool, inWidth, inHeight, sampleSize, decodeFormat);
+ downsampleWithSize(stream, options, pool, inWidth, inHeight, sampleSize,
+ decodeFormat);
- // BitmapDecoder swallows exceptions during decodes and in some cases when inBitmap is non null, may catch
+ // BitmapFactory swallows exceptions during decodes and in some cases when inBitmap is non null, may catch
// and log a stack trace but still return a non null bitmap. To avoid displaying partially decoded bitmaps,
// we catch exceptions reading from the stream in our ExceptionCatchingInputStream and throw them here.
final Exception streamException = stream.getException();
@@ -185,8 +187,8 @@ public abstract class Downsampler implements BitmapDecoder<InputStream> {
return Math.max(1, powerOfTwoSampleSize);
}
- protected Bitmap downsampleWithSize(InputStream is, BitmapFactory.Options options,
- BitmapPool pool, int inWidth, int inHeight, int sampleSize, DecodeFormat decodeFormat) {
+ private Bitmap downsampleWithSize(ExceptionCatchingInputStream is, BitmapFactory.Options options, BitmapPool pool,
+ int inWidth, int inHeight, int sampleSize, DecodeFormat decodeFormat) {
// Prior to KitKat, the inBitmap size must exactly match the size of the bitmap we're decoding.
Bitmap.Config config = getConfig(is, decodeFormat);
options.inSampleSize = sampleSize;
@@ -280,15 +282,14 @@ public abstract class Downsampler implements BitmapDecoder<InputStream> {
* android.graphics.BitmapFactory.Options)}.
* @return an array containing the dimensions of the image in the form {width, height}.
*/
- public int[] getDimensions(InputStream is, BitmapFactory.Options options) {
+ public int[] getDimensions(ExceptionCatchingInputStream is, BitmapFactory.Options options) {
options.inJustDecodeBounds = true;
decodeStream(is, options);
options.inJustDecodeBounds = false;
return new int[] { options.outWidth, options.outHeight };
}
-
- private static Bitmap decodeStream(InputStream is, BitmapFactory.Options options) {
+ private static Bitmap decodeStream(ExceptionCatchingInputStream is, BitmapFactory.Options options) {
if (options.inJustDecodeBounds) {
// This is large, but jpeg headers are not size bounded so we need something large enough to minimize
// the possibility of not being able to fit enough of the header in the buffer to get the image size so
@@ -296,6 +297,11 @@ public abstract class Downsampler implements BitmapDecoder<InputStream> {
// original size each time we use up the buffer space without passing the mark so this is a maximum
// bound on the buffer size, not a default. Most of the time we won't go past our pre-allocated 16kb.
is.mark(MARK_POSITION);
+ } else {
+ // Once we've read the image header, we no longer need to allow the buffer to expand in size. To avoid
+ // unnecessary allocations reading image data, we fix the mark limit so that it is no larger than our
+ // current buffer size here. See issue #225.
+ is.fixMarkLimit();
}
final Bitmap result = BitmapFactory.decodeStream(is, null, options);
diff --git a/library/src/main/java/com/bumptech/glide/load/resource/bitmap/RecyclableBufferedInputStream.java b/library/src/main/java/com/bumptech/glide/load/resource/bitmap/RecyclableBufferedInputStream.java
index b0811526..8699022b 100644
--- a/library/src/main/java/com/bumptech/glide/load/resource/bitmap/RecyclableBufferedInputStream.java
+++ b/library/src/main/java/com/bumptech/glide/load/resource/bitmap/RecyclableBufferedInputStream.java
@@ -17,6 +17,8 @@ package com.bumptech.glide.load.resource.bitmap;
* limitations under the License.
*/
+import android.util.Log;
+
import java.io.FilterInputStream;
import java.io.IOException;
import java.io.InputStream;
@@ -36,32 +38,33 @@ import java.io.InputStream;
* </pre>
*/
public class RecyclableBufferedInputStream extends FilterInputStream {
+ private static final String TAG = "BufferedIs";
/**
* The buffer containing the current bytes read from the target InputStream.
*/
- protected volatile byte[] buf;
+ private volatile byte[] buf;
/**
* The total number of bytes inside the byte array {@code buf}.
*/
- protected int count;
+ private int count;
/**
* The current limit, which when passed, invalidates the current mark.
*/
- protected int marklimit;
+ private int marklimit;
/**
* The currently marked position. -1 indicates no mark has been set or the
* mark has been invalidated.
*/
- protected int markpos = -1;
+ private int markpos = -1;
/**
* The current position within the byte array {@code buf}.
*/
- protected int pos;
+ private int pos;
public RecyclableBufferedInputStream(InputStream in, byte[] buffer) {
super(in);
@@ -95,6 +98,17 @@ public class RecyclableBufferedInputStream extends FilterInputStream {
}
/**
+ * Reduces the mark limit to match the current buffer length to prevent the buffer from
+ * continuing to increase in size.
+ *
+ * <p>Subsequent calls to {@link #mark(int)} will be obeyed and may cause the buffer size
+ * to increase.
+ */
+ public synchronized void fixMarkLimit() {
+ marklimit = buf.length;
+ }
+
+ /**
* Closes this stream. The source stream is closed and any resources
* associated with it are released.
*
@@ -134,6 +148,9 @@ public class RecyclableBufferedInputStream extends FilterInputStream {
if (newLength > marklimit) {
newLength = marklimit;
}
+ if (Log.isLoggable(TAG, Log.DEBUG)) {
+ Log.d(TAG, "allocate buffer of length: " + newLength);
+ }
byte[] newbuf = new byte[newLength];
System.arraycopy(localBuf, 0, newbuf, 0, localBuf.length);
// Reassign buf, which will invalidate any local references
diff --git a/library/src/main/java/com/bumptech/glide/util/ExceptionCatchingInputStream.java b/library/src/main/java/com/bumptech/glide/util/ExceptionCatchingInputStream.java
index 12df71c3..344a2894 100644
--- a/library/src/main/java/com/bumptech/glide/util/ExceptionCatchingInputStream.java
+++ b/library/src/main/java/com/bumptech/glide/util/ExceptionCatchingInputStream.java
@@ -1,5 +1,7 @@
package com.bumptech.glide.util;
+import com.bumptech.glide.load.resource.bitmap.RecyclableBufferedInputStream;
+
import java.io.IOException;
import java.io.InputStream;
import java.util.Queue;
@@ -15,10 +17,10 @@ public class ExceptionCatchingInputStream extends InputStream {
private static final Queue<ExceptionCatchingInputStream> QUEUE = Util.createQueue(0);
- private InputStream wrapped;
+ private RecyclableBufferedInputStream wrapped;
private IOException exception;
- public static ExceptionCatchingInputStream obtain(InputStream toWrap) {
+ public static ExceptionCatchingInputStream obtain(RecyclableBufferedInputStream toWrap) {
ExceptionCatchingInputStream result;
synchronized (QUEUE) {
result = QUEUE.poll();
@@ -41,7 +43,7 @@ public class ExceptionCatchingInputStream extends InputStream {
// Do nothing.
}
- void setInputStream(InputStream toWrap) {
+ void setInputStream(RecyclableBufferedInputStream toWrap) {
wrapped = toWrap;
}
@@ -118,6 +120,10 @@ public class ExceptionCatchingInputStream extends InputStream {
return result;
}
+ public void fixMarkLimit() {
+ wrapped.fixMarkLimit();
+ }
+
public IOException getException() {
return exception;
}