Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

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
like image 744
JibW Avatar asked Jun 21 '13 13:06

JibW


2 Answers

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 ...

like image 81
gunar Avatar answered Sep 18 '22 16:09

gunar


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));
                }
like image 40
Sunil Kumar Avatar answered Sep 19 '22 16:09

Sunil Kumar