Android error: java.lang.OutOfMemoryError: bitmap size exceeds VM budget
Asked Answered
Q

3

5

I came across many questions in stackoverflow regarding this error but non of them found explaining a proper solution for my scenario.

In my android application I have to allow the user to click a button to open the Gallery and to select an image. And then needs to load that specific selected image to an ImageView in my layout(UI).

Doing this is quite fine. Following is the code I am using to achieve this.

In Upload button click ->

        Intent intent = new Intent();
        intent.setType("image/*");
        intent.setAction(Intent.ACTION_GET_CONTENT);
        startActivityForResult(Intent.createChooser(intent,"Select Picture"), REQUEST_UPLOAD_IMG);

And then onActivityResult ->

@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) 
{       
    //super.onActivityResult(requestCode, resultCode, data);        
    if(resultCode == Activity.RESULT_OK)
    {
        if(requestCode==REQUEST_UPLOAD_IMG)
        {               
            Uri selectedImageURI = data.getData();
            uploadImgVW.setImageURI(selectedImageURI);              
        }
        else
        {
            Toast.makeText(MainActivity.this, "You can only select an Image.", Toast.LENGTH_LONG).show();
        }
    }
}

But if user select an image with a higher size (Like 2MB of size), the application quit with the following Error. But It's quite fine with normal(KB level) images and wonder what I can do for this issue(To handle this error situation). Thanks...

Error ->

06-20 16:43:58.445: E/AndroidRuntime(2075): FATAL EXCEPTION: main
06-20 16:43:58.445: E/AndroidRuntime(2075): java.lang.OutOfMemoryError: bitmap size exceeds VM budget
Queeniequeenly answered 21/6, 2013 at 13:19 Comment(4)
You should possibly recycle it every time the bitmap is loaded if(bitmap !=null){ bitmap.recycle();Photomultiplier
The app crashes even from the first time. That's the problem. I added the following codes as well, just to execute garbage collector in the button click. [ System.gc(); Runtime.getRuntime().gc(); ]Queeniequeenly
@Queeniequeenly garbage collection is not the problem, you need to adjust the size of the image like gunnar saysRejection
you should check this question, I posted a sample example to efficiently load large bitmaps : #20692885Entoil
F
7

There are a series of articles that describe how to manage the bitmaps efficiently. Looking at your code, you load the image without knowing how big that is and you will eventually face these issues especially if you load and process many images.

The idea described in one of those articles is to load an already scaled-down Bitmap (first you check how big is the image to load, then you compute the down-scaling factor and only afterwards you'll load the scaled down-image). For that you need to know the dimensions of the ImageView first, then you'll have to use BitmapFactory.decode(...) since you have an Uri of the target file to display. Uri to file should be trivial.

Also, you need to check the memory consumption on your app as well ... you might have other resources that are hanging in the memory and you need to clean them up. I am using a very helpful tool - MAT. A very good article on this can be found here. The author, Patrick Dubroy, held a very interesting session at Google IO 2011 on this topic. Check that out, for me it was very helpful ...

Fairyfairyland answered 21/6, 2013 at 13:32 Comment(0)
T
1

resize the image and then set

public static Bitmap decodeUri(Context c, Uri uri, final int requiredSize) 
            throws FileNotFoundException {
        BitmapFactory.Options o = new BitmapFactory.Options();
        o.inJustDecodeBounds = true;
        BitmapFactory.decodeStream(c.getContentResolver().openInputStream(uri), null, o);

        int width_tmp = o.outWidth
                , height_tmp = o.outHeight;
        int scale = 1;

        while(true) {
            if(width_tmp / 2 < requiredSize || height_tmp / 2 < requiredSize)
                break;
            width_tmp /= 2;
            height_tmp /= 2;
            scale *= 2;
        }

        BitmapFactory.Options o2 = new BitmapFactory.Options();
        o2.inSampleSize = scale;
        return BitmapFactory.decodeStream(c.getContentResolver().openInputStream(uri), null, o2);
    }   

or you can use like that

if(resultCode == RESULT_OK){  
                Uri selectedImage = data.getData();
                InputStream imageStream = null;
                try {
                    imageStream = getContentResolver().openInputStream(selectedImage);
                } catch (FileNotFoundException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
                Bitmap yourSelectedImage = BitmapFactory.decodeStream(imageStream);
                profileImage.setImageBitmap(Bitmap.createScaledBitmap(yourSelectedImage , 120, 120, false));
                }
Thickskinned answered 21/6, 2013 at 13:35 Comment(0)
B
0

You may try this...

BitmapFactory.Options options = new BitmapFactory.Options();
options.inTempStorage = new byte[16*1024];

Bitmap bitmapImage = BitmapFactory.decodeFile(path, options);
Bioluminescence answered 21/6, 2013 at 13:38 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.