提交 ae05603c 编写于 作者: R Robert Papp 提交者: Sam Judd

Release some dangling pool resources in finally blocks and reuse local...

Release some dangling pool resources in finally blocks and reuse local variables instead of getters.
上级 9e52382f
package com.bumptech.glide.load.model;
import android.util.Log;
import com.bumptech.glide.load.Encoder;
import com.bumptech.glide.util.ByteArrayPool;
......@@ -11,21 +13,25 @@ import java.io.OutputStream;
* An {@link com.bumptech.glide.load.Encoder} that can write an {@link java.io.InputStream} to disk.
*/
public class StreamEncoder implements Encoder<InputStream> {
private static final String TAG = "StreamEncoder";
@Override
public boolean encode(InputStream data, OutputStream os) {
byte[] buffer = ByteArrayPool.get().getBytes();
int read;
try {
int read;
while ((read = data.read(buffer)) != -1) {
os.write(buffer, 0, read);
}
return true;
} catch (IOException e) {
e.printStackTrace();
if (Log.isLoggable(TAG, Log.ERROR)) {
Log.v(TAG, "Failed to encode data onto the OutputStream", e);
}
return false;
} finally {
ByteArrayPool.get().releaseBytes(buffer);
}
ByteArrayPool.get().releaseBytes(buffer);
return true;
}
@Override
......
......@@ -121,66 +121,79 @@ public abstract class Downsampler implements BitmapDecoder<InputStream> {
* Load the image for the given InputStream. If a recycled Bitmap whose dimensions exactly match those of the image
* for the given InputStream is available, the operation is much less expensive in terms of memory.
*
* Note - this method will throw an exception of a Bitmap with dimensions not matching those of the image for the
* given InputStream is provided.
* <p>
* Note - this method will throw an exception of a Bitmap with dimensions not matching
* those of the image for the given InputStream is provided.
* </p>
*
* @param is An InputStream to the data for the image
* @param is An {@link InputStream} to the data for the image
* @param pool A pool of recycled bitmaps
* @param outWidth The width the final image should be close to
* @param outHeight The height the final image should be close to
* @return A new bitmap containing the image from the given InputStream, or recycle if recycle is not null
*/
@SuppressWarnings("resource")
// see BitmapDecoder.decode
@Override
public Bitmap decode(InputStream is, BitmapPool pool, int outWidth, int outHeight, DecodeFormat decodeFormat) {
final ByteArrayPool byteArrayPool = ByteArrayPool.get();
byte[] bytesForOptions = byteArrayPool.getBytes();
byte[] bytesForStream = byteArrayPool.getBytes();
RecyclableBufferedInputStream bis = new RecyclableBufferedInputStream(is, bytesForStream);
bis.mark(MARK_POSITION);
int orientation = 0;
try {
orientation = new ImageHeaderParser(bis).getOrientation();
} catch (IOException e) {
e.printStackTrace();
}
final byte[] bytesForOptions = byteArrayPool.getBytes();
final byte[] bytesForStream = byteArrayPool.getBytes();
final BitmapFactory.Options options = getDefaultOptions();
final RecyclableBufferedInputStream bis = new RecyclableBufferedInputStream(is, bytesForStream);
try {
bis.reset();
} catch (IOException e) {
e.printStackTrace();
}
bis.mark(MARK_POSITION);
int orientation = 0;
try {
orientation = new ImageHeaderParser(bis).getOrientation();
} catch (IOException e) {
if (Log.isLoggable(TAG, Log.WARN)) {
Log.w(TAG, "Cannot determine the image orientation from header", e);
}
} finally {
try {
bis.reset();
} catch (IOException e) {
if (Log.isLoggable(TAG, Log.WARN)) {
Log.w(TAG, "Cannot reset the input stream", e);
}
}
}
final BitmapFactory.Options options = getDefaultOptions();
options.inTempStorage = bytesForOptions;
final int[] inDimens = getDimensions(bis, options);
final int inWidth = inDimens[0];
final int inHeight = inDimens[1];
final int degreesToRotate = TransformationUtils.getExifOrientationDegrees(orientation);
final int sampleSize;
if (degreesToRotate == 90 || degreesToRotate == 270) {
// If we're rotating the image +-90 degrees, we need to downsample accordingly so the image width is
// decreased to near our target's height and the image height is decreased to near our target width.
sampleSize = getSampleSize(inHeight, inWidth, outWidth, outHeight);
} else {
sampleSize = getSampleSize(inWidth, inHeight, outWidth, outHeight);
}
options.inTempStorage = bytesForOptions;
final Bitmap downsampled = downsampleWithSize(bis, options, pool, inWidth, inHeight, sampleSize, decodeFormat);
final int[] inDimens = getDimensions(bis, options);
final int inWidth = inDimens[0];
final int inHeight = inDimens[1];
Bitmap rotated = null;
if (downsampled != null) {
rotated = TransformationUtils.rotateImageExif(downsampled, pool, orientation);
final int degreesToRotate = TransformationUtils.getExifOrientationDegrees(orientation);
final int sampleSize;
if (degreesToRotate == 90 || degreesToRotate == 270) {
// If we're rotating the image +-90 degrees, we need to downsample accordingly so the image width is
// decreased to near our target's height and the image height is decreased to near our target width.
sampleSize = getSampleSize(inHeight, inWidth, outWidth, outHeight);
} else {
sampleSize = getSampleSize(inWidth, inHeight, outWidth, outHeight);
}
final Bitmap downsampled =
downsampleWithSize(bis, options, pool, inWidth, inHeight, sampleSize, decodeFormat);
if (downsampled != rotated && !pool.put(downsampled)) {
downsampled.recycle();
Bitmap rotated = null;
if (downsampled != null) {
rotated = TransformationUtils.rotateImageExif(downsampled, pool, orientation);
if (downsampled != rotated && !pool.put(downsampled)) {
downsampled.recycle();
}
}
}
byteArrayPool.releaseBytes(bytesForOptions);
byteArrayPool.releaseBytes(bytesForStream);
releaseOptions(options);
return rotated;
return rotated;
} finally {
byteArrayPool.releaseBytes(bytesForOptions);
byteArrayPool.releaseBytes(bytesForStream);
releaseOptions(options);
}
}
protected Bitmap downsampleWithSize(RecyclableBufferedInputStream bis, BitmapFactory.Options options,
......@@ -210,12 +223,16 @@ public abstract class Downsampler implements BitmapDecoder<InputStream> {
// look at : https://groups.google.com/forum/#!msg/android-developers/Mp0MFVFi1Fo/e8ZQ9FGdWdEJ
return TYPES_THAT_USE_POOL.contains(type);
} catch (IOException e) {
e.printStackTrace();
if (Log.isLoggable(TAG, Log.WARN)) {
Log.w(TAG, "Cannot determine the image type from header", e);
}
} finally {
try {
bis.reset();
} catch (IOException e) {
e.printStackTrace();
if (Log.isLoggable(TAG, Log.WARN)) {
Log.w(TAG, "Cannot reset the input stream", e);
}
}
}
return false;
......@@ -232,12 +249,16 @@ public abstract class Downsampler implements BitmapDecoder<InputStream> {
try {
hasAlpha = new ImageHeaderParser(bis).hasAlpha();
} catch (IOException e) {
e.printStackTrace();
if (Log.isLoggable(TAG, Log.WARN)) {
Log.w(TAG, "Cannot determine whether the image has alpha or not from header for format " + format, e);
}
} finally {
try {
bis.reset();
} catch (IOException e) {
e.printStackTrace();
if (Log.isLoggable(TAG, Log.WARN)) {
Log.w(TAG, "Cannot reset the input stream", e);
}
}
}
......@@ -292,8 +313,6 @@ public abstract class Downsampler implements BitmapDecoder<InputStream> {
if (options.inJustDecodeBounds) {
bis.reset();
bis.clearMark();
} else {
bis.close();
}
} catch (IOException e) {
if (Log.isLoggable(TAG, Log.ERROR)) {
......
......@@ -27,13 +27,15 @@ public class ImageVideoBitmapDecoder implements ResourceDecoder<ImageVideoWrappe
this.fileDescriptorDecoder = fileDescriptorDecoder;
}
@SuppressWarnings("resource")
// @see ResourceDecoder.decode
@Override
public Resource<Bitmap> decode(ImageVideoWrapper source, int width, int height) throws IOException {
Resource<Bitmap> result = null;
InputStream is = source.getStream();
if (is != null) {
try {
result = streamDecoder.decode(source.getStream(), width, height);
result = streamDecoder.decode(is, width, height);
} catch (IOException e) {
if (Log.isLoggable(TAG, Log.VERBOSE)) {
Log.v(TAG, "Failed to load image from stream, trying FileDescriptor", e);
......@@ -44,7 +46,7 @@ public class ImageVideoBitmapDecoder implements ResourceDecoder<ImageVideoWrappe
if (result == null) {
ParcelFileDescriptor fileDescriptor = source.getFileDescriptor();
if (fileDescriptor != null) {
result = fileDescriptorDecoder.decode(source.getFileDescriptor(), width, height);
result = fileDescriptorDecoder.decode(fileDescriptor, width, height);
}
}
return result;
......
......@@ -31,7 +31,7 @@ public class GifResourceDecoder implements ResourceDecoder<InputStream, GifDrawa
private static final GifHeaderParserPool PARSER_POOL = new DefaultGifHeaderParserPool();
private final Context context;
private final BitmapPool bitmapPool;
private GifHeaderParserPool parserPool;
private final GifHeaderParserPool parserPool;
public GifResourceDecoder(Context context) {
this(context, Glide.get(context).getBitmapPool());
......@@ -94,11 +94,11 @@ public class GifResourceDecoder implements ResourceDecoder<InputStream, GifDrawa
}
private static byte[] inputStreamToBytes(InputStream is) {
int capacity = 16384;
ByteArrayOutputStream buffer = new ByteArrayOutputStream(capacity);
final int bufferSize = 16384, initialCapacity = bufferSize;
ByteArrayOutputStream buffer = new ByteArrayOutputStream(initialCapacity);
try {
int nRead;
byte[] data = new byte[16384];
byte[] data = new byte[bufferSize];
while ((nRead = is.read(data, 0, data.length)) != -1) {
buffer.write(data, 0, nRead);
}
......@@ -106,6 +106,7 @@ public class GifResourceDecoder implements ResourceDecoder<InputStream, GifDrawa
} catch (IOException e) {
Log.w(TAG, "Error reading data from stream", e);
}
//TODO the returned byte[] may be partial if an IOException was thrown from read
return buffer.toByteArray();
}
......
......@@ -28,32 +28,37 @@ public class GifBitmapWrapperResourceDecoder implements ResourceDecoder<ImageVid
this.gifDecoder = gifDecoder;
}
@SuppressWarnings("resource")
// @see ResourceDecoder.decode
@Override
public Resource<GifBitmapWrapper> decode(ImageVideoWrapper source, int width, int height) throws IOException {
ByteArrayPool pool = ByteArrayPool.get();
InputStream is = source.getStream();
byte[] tempBytes = pool.getBytes();
RecyclableBufferedInputStream bis = new RecyclableBufferedInputStream(is, tempBytes);
GifBitmapWrapper result = null;
if (is != null) {
source = new ImageVideoWrapper(bis, source.getFileDescriptor());
// 2048 is rather arbitrary, for most well formatted image types we only need 32 bytes.
bis.mark(2048);
ImageHeaderParser.ImageType type = new ImageHeaderParser(bis).getType();
bis.reset();
try {
GifBitmapWrapper result = null;
if (is != null) {
source = new ImageVideoWrapper(bis, source.getFileDescriptor());
// 2048 is rather arbitrary, for most well formatted image types we only need 32 bytes.
bis.mark(2048);
ImageHeaderParser.ImageType type = new ImageHeaderParser(bis).getType();
bis.reset();
if (type == ImageHeaderParser.ImageType.GIF) {
Resource<GifDrawable> gifResource = gifDecoder.decode(bis, width, height);
result = new GifBitmapWrapper(null, gifResource);
if (type == ImageHeaderParser.ImageType.GIF) {
Resource<GifDrawable> gifResource = gifDecoder.decode(bis, width, height);
result = new GifBitmapWrapper(null, gifResource);
}
}
}
if (result == null) {
Resource<Bitmap> bitmapResource = bitmapDecoder.decode(source, width, height);
result = new GifBitmapWrapper(bitmapResource, null);
if (result == null) {
Resource<Bitmap> bitmapResource = bitmapDecoder.decode(source, width, height);
result = new GifBitmapWrapper(bitmapResource, null);
}
return new GifBitmapWrapperResource(result);
} finally {
pool.releaseBytes(tempBytes);
}
pool.releaseBytes(tempBytes);
return new GifBitmapWrapperResource(result);
}
@Override
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册