Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Catching OutOfMemoryError in decoding Bitmap

Is it a good practice to catch OutOfMemoryError even you have tried some ways to reduce memory usage? Or should we just not catching the exception? Which one is better practice?

try {
    BitmapFactory.Options options = new BitmapFactory.Options();
    options.inSampleSize = 4;
    bitmap = BitmapFactory.decodeFile(file, options);
} catch (OutOfMemoryError e) {
    e.printStackTrace();
}

Thanks

like image 560
bitbybit Avatar asked Aug 21 '11 13:08

bitbybit


2 Answers

It's good practice to catch it once and give decodeFile another chance. Catch it and call System.gc() and try decoding again. There is a high probability that it will work after calling System.gc().

try {
    BitmapFactory.Options options = new BitmapFactory.Options();
    options.inSampleSize = 4;
    bitmap = BitmapFactory.decodeFile(file, options);
 } catch (OutOfMemoryError e) {
    e.printStackTrace();

    System.gc();

    try {
        bitmap = BitmapFactory.decodeFile(file);
    } catch (OutOfMemoryError e2) {
      e2.printStackTrace();
      // handle gracefully.
    }
}
like image 70
Ronnie Avatar answered Nov 15 '22 23:11

Ronnie


I did something like this: I catch the error only for try to scale down the image until it works. Eventually it can not work at all; then returns null; otherwise, in success, returns the bitmap.

Outside I decide what to do with the bitmap whether it's null or not.

// Let w and h the width and height of the ImageView where we will place the Bitmap. Then:

// Get the dimensions of the original bitmap
BitmapFactory.Options bmOptions= new BitmapFactory.Options();
bmOptions.inJustDecodeBounds= true;
BitmapFactory.decodeFile(path, bmOptions);
int photoW= bmOptions.outWidth;
int photoH= bmOptions.outHeight;

// Determine how much to scale down the image. 
int scaleFactor= (int) Math.max(1.0, Math.min((double) photoW / (double)w, (double)photoH / (double)h));    //1, 2, 3, 4, 5, 6, ...
scaleFactor= (int) Math.pow(2.0, Math.floor(Math.log((double) scaleFactor) / Math.log(2.0)));               //1, 2, 4, 8, ...

// Decode the image file into a Bitmap sized to fill the View
bmOptions.inJustDecodeBounds= false;
bmOptions.inSampleSize= scaleFactor;
bmOptions.inPurgeable= true;

do
{
    try
    {
        Log.d("tag", "scaleFactor: " + scaleFactor);
        scaleFactor*= 2;
        bitmap= BitmapFactory.decodeFile(path, bmOptions);
    }
    catch(OutOfMemoryError e)
    {
        bmOptions.inSampleSize= scaleFactor;
        Log.d("tag", "OutOfMemoryError: " + e.toString());
    }
}
while(bitmap == null && scaleFactor <= 256);

if(bitmap == null)
    return null;

For example, with an image of 3264x2448, the loop iterates 2 times on my phone, and then it works.

like image 42
jsanmarb Avatar answered Nov 15 '22 22:11

jsanmarb