vxhviet
6/23/2016 - 5:32 AM

Avoid OOM with BItmap

Avoid OOM with BItmap

Source: StackOverflow

Question: How to avoid Out Of Memory error on Android when dealing with bitmap.

Answer: Unless you're absolutely sure the Bitmap is small then instead of using this generic method to load Bitmap from resource:

Bitmap bitmap = MediaStore.Images.Media.getBitmap(this.getContentResolver(), imageUri);

Use this one to subsample the image to a smaller one with good enough quality for displaying:

    public static final int BITMAP_THRESHOLD = 500; //maximum dimension for subsampled bitmap

    public static Bitmap loadSubsampledBitmap(Context ctx, Uri uri, int threshold) throws FileNotFoundException, IOException{
        InputStream input = ctx.getContentResolver().openInputStream(uri);

        BitmapFactory.Options onlyBoundsOptions = new BitmapFactory.Options();
        onlyBoundsOptions.inJustDecodeBounds = true;
        onlyBoundsOptions.inDither=true;//optional
        onlyBoundsOptions.inPreferredConfig=Bitmap.Config.ARGB_8888;//optional
        BitmapFactory.decodeStream(input, null, onlyBoundsOptions);
        input.close();
        if ((onlyBoundsOptions.outWidth == -1) || (onlyBoundsOptions.outHeight == -1))
            return null;

        Log.d(TAG, "TEST_SUBSAMPLE original width: " + onlyBoundsOptions.outWidth + " height: " + onlyBoundsOptions.outHeight);
        int originalSize = (onlyBoundsOptions.outHeight > onlyBoundsOptions.outWidth) ? onlyBoundsOptions.outHeight : onlyBoundsOptions.outWidth;

        double ratio = (originalSize > threshold) ? (originalSize / threshold) : 1.0;

        BitmapFactory.Options bitmapOptions = new BitmapFactory.Options();
        bitmapOptions.inSampleSize = getPowerOfTwoForSampleRatio(ratio);
        bitmapOptions.inDither=true;//optional
        bitmapOptions.inPreferredConfig=Bitmap.Config.ARGB_8888;//optional
        input = ctx.getContentResolver().openInputStream(uri);
        Bitmap bitmap = BitmapFactory.decodeStream(input, null, bitmapOptions);
        input.close();
        Log.d(TAG, "TEST_SUBSAMPLE subsampled  width: " + bitmap.getWidth() + " height: " + bitmap.getHeight());
        return bitmap;
    }

    private static int getPowerOfTwoForSampleRatio(double ratio){
        int k = Integer.highestOneBit((int)Math.floor(ratio));
        if(k==0) return 1;
        else return k;
    }