我有一堆图片网址。我必须下载这些图像并逐个显示在我的应用程序中。我使用SoftReferences
和Sdcard将图像保存在集合中以避免重新获取并改善用户体验。
问题是我对位图的大小一无所知。事实证明,当我使用BitmapFactory.decodeStream(InputStream)
方法时,偶尔会出现OutOfMemoryExceptions。因此,我选择使用BitmapFactory Options(样本大小= 2)对图像进行下采样。这提供了更好的输出:没有OOM,但这会影响较小图像的质量。
我该如何处理这类案件?有没有办法选择性地仅对高分辨率图像进行下采样?
答案 0 :(得分:55)
BitmapFactory.Options
类(我忽略了一个)中有一个名为inJustDecodeBounds
的选项,其中javadoc为:
如果设置为true,解码器将 返回null(没有位图),但是 out ...字段仍将设置, 允许调用者查询 位图而不必分配 内存为其像素。
我用它来找出Bitmap的实际大小,然后选择使用inSampleSize
选项对其进行下采样。这至少可以避免在解码文件时出现任何OOM错误。
参考:
1. Handling larger Bitmaps
2. How do I get Bitmap info before I decode
答案 1 :(得分:13)
经过几天努力避免我使用不同设备获得的所有OutOfMemory错误,我创建了这个:
private Bitmap getDownsampledBitmap(Context ctx, Uri uri, int targetWidth, int targetHeight) {
Bitmap bitmap = null;
try {
BitmapFactory.Options outDimens = getBitmapDimensions(uri);
int sampleSize = calculateSampleSize(outDimens.outWidth, outDimens.outHeight, targetWidth, targetHeight);
bitmap = downsampleBitmap(uri, sampleSize);
} catch (Exception e) {
//handle the exception(s)
}
return bitmap;
}
private BitmapFactory.Options getBitmapDimensions(Uri uri) throws FileNotFoundException, IOException {
BitmapFactory.Options outDimens = new BitmapFactory.Options();
outDimens.inJustDecodeBounds = true; // the decoder will return null (no bitmap)
InputStream is= getContentResolver().openInputStream(uri);
// if Options requested only the size will be returned
BitmapFactory.decodeStream(is, null, outDimens);
is.close();
return outDimens;
}
private int calculateSampleSize(int width, int height, int targetWidth, int targetHeight) {
int inSampleSize = 1;
if (height > targetHeight || width > targetWidth) {
// Calculate ratios of height and width to requested height and
// width
final int heightRatio = Math.round((float) height
/ (float) targetHeight);
final int widthRatio = Math.round((float) width / (float) targetWidth);
// Choose the smallest ratio as inSampleSize value, this will
// guarantee
// a final image with both dimensions larger than or equal to the
// requested height and width.
inSampleSize = heightRatio < widthRatio ? heightRatio : widthRatio;
}
return inSampleSize;
}
private Bitmap downsampleBitmap(Uri uri, int sampleSize) throws FileNotFoundException, IOException {
Bitmap resizedBitmap;
BitmapFactory.Options outBitmap = new BitmapFactory.Options();
outBitmap.inJustDecodeBounds = false; // the decoder will return a bitmap
outBitmap.inSampleSize = sampleSize;
InputStream is = getContentResolver().openInputStream(uri);
resizedBitmap = BitmapFactory.decodeStream(is, null, outBitmap);
is.close();
return resizedBitmap;
}
此方法适用于我测试过的所有设备,但我认为使用其他我不了解的过程可以提高质量。
我希望我的代码可以在相同的情况下帮助其他开发人员。如果高级开发人员可以提供帮助,我也很感激,并提出有关其他流程的建议,以避免在此过程中损失(较少)质量。
答案 2 :(得分:12)
我自己做的是:
inJustDecodeBounds
获取图片的原始尺寸inSampleSize
(不会降低图像质量的2的幂)。我使用这个功能:int k = Integer.highestOneBit((int)Math.floor(ratio)); if(k==0) return 1; else return k;