按照预期, glide对任何bitmap的使用, 都需要经由LruBitmapPool生成.
但是最近在调试代码的时候, 也发现了一些异常的现象:
明明bitmapPool借出bitmap对象的时候, 尺寸大小是a, 但是后面归还给bitmapPool的对象尺寸却出现了b大小.
这很让人费解.
调试了一晚上, 才发现, 由于有些图片本身格式有问题, 比如不完整. 会导致在Downsampler.java中的decodeStream()中出现异常.
private static Bitmap decodeStream(InputStream is, BitmapFactory.Options options,
DecodeCallbacks callbacks, BitmapPool bitmapPool) throws IOException {
if (options.inJustDecodeBounds) {
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. We need to do so immediately before
// decoding the full image to avoid having our mark limit overridden by other calls to
// mark and reset. See issue #225.
callbacks.onObtainBounds();
}
// BitmapFactory.Options out* variables are reset by most calls to decodeStream, successful or
// otherwise, so capture here in case we log below.
int sourceWidth = options.outWidth;
int sourceHeight = options.outHeight;
String outMimeType = options.outMimeType;
final Bitmap result;
TransformationUtils.getBitmapDrawableLock().lock();
try {
result = BitmapFactory.decodeStream(is, null, options);
} catch (IllegalArgumentException e) {
IOException bitmapAssertionException =
newIoExceptionForInBitmapAssertion(e, sourceWidth, sourceHeight, outMimeType, options);
if (Log.isLoggable(TAG, Log.DEBUG)) {
Log.d(TAG, "Failed to decode with inBitmap, trying again without Bitmap re-use",
bitmapAssertionException);
}
if (options.inBitmap != null) {
try {
is.reset();
bitmapPool.put(options.inBitmap);
options.inBitmap = null;
return decodeStream(is, options, callbacks, bitmapPool);
} catch (IOException resetException) {
throw bitmapAssertionException;
}
}
throw bitmapAssertionException;
} finally {
TransformationUtils.getBitmapDrawableLock().unlock();
}
if (options.inJustDecodeBounds) {
is.reset();
}
return result;
}
注意上面的那个catch()分支, 如果进入之后, 会把之前从bitmapPool中借出的bitmap对象( options.inBitmap) 归还. 然后继续重新加载图片, 这是这次加载, 就是纯新建的bitmap了, 不是bitmapPool中的对象了.
而后续的流程, 并不知晓这个情况, 导致会在某个节点, 仍然把此处新生成的bitmap对象, 归还给bitmapPool.
于是就出现了开头所说的现象.
这里列出具体的exception:
07-10 21:07:33.987 8694-9208/com.sogou.luedong E/Downsampler: decodeStream:
java.lang.IllegalArgumentException: Problem decoding into existing bitmap
从网上查, 也能查到很多关于这个报错的问题:
https://stackoverflow.com/questions/16034756/why-does-decoding-bitmap-with-inbitmap-always-get-java-lang-illegalargumentexcep
https://github.com/facebook/fresco/issues/1204
想了想, 也并没有什么更好的办法解决, 对于出现异常之后的这种流程, 既然bitmap已经新生成了, 放入bitmapPool是最好的选择. 因为后续保不齐就真的能用到.
也许只能从后台数据上下功夫, 去除此类图片. 多半是由于抓取时有问题, 没有抓取完整.
网友评论