MediaStore.Images.Media.getBitmap和内存溢出错误

17

我的代码是:

public Bitmap loadPhoto(Uri uri) {
    Bitmap scaled = null;
    try {
    scalled = Bitmap.createBitmap(
      MediaStore.Images.Media.getBitmap(getContentResolver(), uri),
      0,0,90, 90);

    if (scaled == null) { return null; }
    } catch(Exception e) { }
    return scaled;
}

在这之后,我将图像缩放并显示在 ImageView 中。每个图像都来自设备相机。

每次从相机获取三张照片后,我都会出现 内存不足 错误。如何解决?


1
我曾经遇到过同样的问题,可以查看以下链接: http://tutorials-android.blogspot.co.il/2011/11/outofmemory-exception-when-decoding.html - zwebie
1
还可以参考Chet Haase关于位图缩放的优秀教程:http://www.youtube.com/watch?v=12cB7gnL6po - Peter Tran
2
请注意此页面已非常过时-今天您只需执行以下操作:https://dev59.com/VWAf5IYBdhLWcg3w7mU_#24135522 - Fattie
你有这个问题的答案吗?请分享代码。 - Jyoti Sharma
4个回答

5

Praveen Katha的答案总是返回null, 这里是更新后的答案。

关键是每次使用后关闭输入流。输入流只能使用一次。更多信息,请参考此答案

private static int calculateInSampleSize(
            BitmapFactory.Options options, int reqWidth, int reqHeight) {
        // Raw height and width of image
        final int height = options.outHeight;
        final int width = options.outWidth;
        int inSampleSize = 1;

        if (height > reqHeight || width > reqWidth) {

            final int halfHeight = height / 2;
            final int halfWidth = width / 2;

            // Calculate the largest inSampleSize value that is a power of 2 and keeps both
            // height and width larger than the requested height and width.
            while ((halfHeight / inSampleSize) >= reqHeight
                    && (halfWidth / inSampleSize) >= reqWidth) {
                inSampleSize *= 2;
            }
        }

        return inSampleSize;
    }

    public static Bitmap decodeSampledBitmapFromUri(Context context, Uri imageUri, int reqWidth, int reqHeight) throws FileNotFoundException {
        Bitmap bitmap = null;
        try {
            // Get input stream of the image
            final BitmapFactory.Options options = new BitmapFactory.Options();
            InputStream iStream = context.getContentResolver().openInputStream(imageUri);

            // First decode with inJustDecodeBounds=true to check dimensions
            options.inJustDecodeBounds = true;
            BitmapFactory.decodeStream(iStream, null, options);
            if (iStream != null) {
                iStream.close();
            }
            iStream = context.getContentResolver().openInputStream(imageUri);

            // Calculate inSampleSize
            options.inSampleSize = calculateInSampleSize(options, reqWidth, reqHeight);

            // Decode bitmap with inSampleSize set
            options.inJustDecodeBounds = false;
            bitmap = BitmapFactory.decodeStream(iStream, null, options);
            if (iStream != null) {
                iStream.close();
            }
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return bitmap;
    }

1
对于那些正在寻找代码示例的人:

private static int calculateInSampleSize(
        BitmapFactory.Options options, int reqWidth, int reqHeight) {
    // Raw height and width of image
    final int height = options.outHeight;
    final int width = options.outWidth;
    int inSampleSize = 1;

    if (height > reqHeight || width > reqWidth) {

        final int halfHeight = height / 2;
        final int halfWidth = width / 2;

        // Calculate the largest inSampleSize value that is a power of 2 and keeps both
        // height and width larger than the requested height and width.
        while ((halfHeight / inSampleSize) >= reqHeight
                && (halfWidth / inSampleSize) >= reqWidth) {
            inSampleSize *= 2;
        }
    }

    return inSampleSize;
}

public static Bitmap decodeSampledBitmapFromUri(Context context, Uri imageUri, int reqWidth, int reqHeight) throws FileNotFoundException {

    // Get input stream of the image
    final BitmapFactory.Options options = new BitmapFactory.Options();
    InputStream iStream = context.getContentResolver().openInputStream(imageUri);

    // First decode with inJustDecodeBounds=true to check dimensions
    options.inJustDecodeBounds = true;
    BitmapFactory.decodeStream(iStream, null, options);

    // Calculate inSampleSize
    options.inSampleSize = calculateInSampleSize(options, reqWidth, reqHeight);

    // Decode bitmap with inSampleSize set
    options.inJustDecodeBounds = false;
    return BitmapFactory.decodeStream(iStream, null, options);
}

1
你真的尝试过这个函数吗?我尝试了一下,发现decodeSampledBitmapFromUri函数总是返回null。经过长时间的研究,我发现你不能将同一个inputstream作为参数传递给BitmapFactory.decodeStream超过一次。 - Dika
刚刚意识到这个问题。第一次调用后,输入流指向文件末尾。可能有一种方法可以重置它而不是创建一个新的... - hippietrail


0

MediaStore.getBitmap方法是一个方便的方法,获取位图时不指定样本大小。如果您正在使用getBitmap(ContentResolver, Uri)并想使用样本大小,只需使用ContentResolver获取输入流,并像通常一样解码位图(首先计算样本大小,然后使用适当的样本大小加载它)。


1
听起来是一个不错的方法,编写代码会使答案更好。 - weston
@weston Google在链接提供了关于高效加载位图的示例代码。可以通过查看MediaStore.getBitmap的实现来了解ContentResolver的使用方法。它以相同的方式调用内容解析器。 - Peter O
2
我知道你可以在其他地方找到答案,因为我已经不得不这样做了,因为答案是不完整的。每个阅读此答案的人都必须做同样的工作。一个好的 Stack Overflow 答案不依赖于外部链接来完成它。 - weston

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接