Loading images throws OutOfMemoryException

629 Views Asked by At

I use the following code to load images to rows in a ListActivity.

URL url = new URL(drink.getImageUri());
                InputStream fis = url.openStream();
                //Decode image size
                BitmapFactory.Options o = new BitmapFactory.Options();
                o.inJustDecodeBounds = true;
                BitmapFactory.decodeStream(fis, null, o);
                int scale = 1;
                if (o.outHeight > imageMaxSize || o.outWidth > imageMaxSize) {
                    scale = (int) Math.pow(2, (int) Math.round(Math.log((imageMaxSize / (double) Math.max(o.outHeight, o.outWidth)) / Math.log(0.5))));
                }
                fis.close();
                fis = url.openStream();
                //Decode with inSampleSize
                BitmapFactory.Options o2 = new BitmapFactory.Options();
                o2.inSampleSize = scale;
                bitmap = BitmapFactory.decodeStream(fis, null, o2);

                fis.close();

imageMaxSize is screenHeight/7 so the each image should be fairly small.

Have I done something wrong in the code above? All errors I got is in the second last line where I attempt to actually load the bitmap.

Thanks in advance Roland

3

There are 3 best solutions below

2
On BEST ANSWER

The problem with the code above whas the following block:

if (o.outHeight > imageMaxSize || o.outWidth > imageMaxSize) {
                    scale = (int) Math.pow(2, (int) Math.round(Math.log((imageMaxSize / (double) Math.max(o.outHeight, o.outWidth)) / Math.log(0.5))));
                }

It simply doesn't do its job. WillyTates comment of trying to increase the scaling made me check the result of the calculation and it always returned 1.

Now when I fixed it so I get scale of 4 or 8 it works a lot better and I havn't been able to get the error back.

Thanks Roland

0
On

I think the key here is that you're doing this on rows of a list. You need to recycle your Bitmaps when you're done with them to clean up the memory. This is probably not happening on the first iteration of your code, but since you're not reclaiming the memory with Bitmap.recycle() eventually you run out of memory and get "Bitmap exceeds VM budget"

0
On

A better answer to the accepted answer.

Basically sometimes because of rounding Math.round(etc) will round the scale back to 1.

1 means NO scaling even though your image is too big.

I do a simple check on the scale after the alogirthm.

    if (o.outHeight > imageMaxSize || o.outWidth > imageMaxSize) {
        scale = (int) Math.pow(2, (int) Math.round(Math.log((imageMaxSize / (double) Math.max(o.outHeight, o.outWidth)) / Math.log(0.5))));
        // We already checked it was larger than acceptable so we know we at
        // least need to scale down one step
        if (scale == 1) {
            scale = 2;
        }

    }