Catching OutOfMemoryError in decoding Bitmap

14,041

Solution 1

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

Solution 2

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.

Share:
14,041

Related videos on Youtube

bitbybit
Author by

bitbybit

Updated on June 10, 2022

Comments

  • bitbybit
    bitbybit about 2 years

    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

  • bitbybit
    bitbybit almost 13 years
    Good catch about the options. Thanks
  • bitbybit
    bitbybit almost 13 years
    Calling System.gc() may not be good idea, http://code.google.com/p/android/issues/detail?id=8488#c80, anyway, thanks
  • Ron
    Ron almost 13 years
    Here you have no worries with that, as you have not loaded the bitmap yet. So its safe to call GC. Just be sure you call bitmap.recycle() when you are finished with it.
  • Edwin Evans
    Edwin Evans over 11 years
    What should you do for "handle gracefully"? I'm not sure how to explain this to users in a friendly manner. Tell them to go to other apps and click Back? Ask them to Reboot?
  • Ron
    Ron over 11 years
    Probably you should try with a higher inSampleSize value the second time. If it doesn't work even after that then you can display a message telling user that the image load operation failed and should try the same actions again..
  • user276648
    user276648 over 9 years
    You could also try adding android:largeHeap="true" in your manifest if you can't/don't want to use a higher inSampleSize.
  • thib_rdr
    thib_rdr over 8 years
    It seems like a good solution, I would like to try it, but cant figure out what w and h variables are at the 7th line ?
  • jsanmarb
    jsanmarb over 8 years
    @GaryHost: w and h are the width and height of the ImageView where we will place the Bitmap. Answer updated.
  • thib_rdr
    thib_rdr over 8 years
    Thanks men, I adopted your solution :)