OutOfMemory (Due to large bitmap) Handling in Android

Here i will explain how you can avoid outOfMemoryError in android, which is very common when app deals with large size bitmaps and when i say large size, there is no magical number to define it though. It actually depends upon various factors like device config, OS version, available RAM ect.

I am assuming that you are already using very basic memory optimizations like releasing resouces/UI elements in onPause() and assigning them back in onResume() .  So i will mainly focus on bitmap optimization.

Typical format of OOM Error can be like :

06-11 14:51:18.976: E/dalvikvm-heap(19566): Out of memory on a 45349648-byte allocation.
06-11 14:51:18.986: E/AndroidRuntime(19566): FATAL EXCEPTION: main
06-11 14:51:18.986: E/AndroidRuntime(19566): java.lang.OutOfMemoryError
06-11 14:51:18.986: E/AndroidRuntime(19566): at android.graphics.BitmapFactory.nativeDecodeAsset(Native Method)
06-11 14:51:18.986: E/AndroidRuntime(19566): at android.graphics.BitmapFactory.decodeStream(BitmapFactory.java:596)

Or

OutofMemoryError: bitmap size exceeds VM budget
ERROR/dalvikvm-heap(1923):925200-byte external allocation too large for this process.

Root cause of the issue is that Runtime Memory allocated to an app is limited (and significantly lesser) and app is trying to use memory beyond that limit. So you will need to scale down images to reduce runtime memory consumption.

Here is how you can do it :

1) If you want to set an image from drawable to ImageView, Do not use ImageView.setImageResource(int resId) directly with drawable id. Instead get Scaled down bitmap(if applicable) and set it to imageView. like this:

iv.setImageBitmap(decodeResource(getResources(), R.drawable.big_image));

private static Bitmap decodeResource(Resources res, int id) {
Bitmap bitmap = null;
BitmapFactory.Options options = new BitmapFactory.Options();
for (options.inSampleSize = 1; options.inSampleSize <= 32; options.inSampleSize++) {
try {
bitmap = BitmapFactory.decodeResource(res, id, options);
Log.d(TAG_LOG, “Decoded successfully for sampleSize ” + options.inSampleSize);
break;
} catch (OutOfMemoryError outOfMemoryError) {
// If an OutOfMemoryError occurred, we continue with for loop and next inSampleSize value
Log.e(TAG_LOG, “outOfMemoryError while reading file for sampleSize ” + options.inSampleSize
+ ” retrying with higher value”);
}
}
return bitmap;
}

2) If you want to read an image from memory, do not use  BitmapFactory.decodeFile(String pathName), Instead use image, scaled down up-to optimal point. like this :

Bitmap bitmap = decodeFile(filePath);

public static Bitmap decodeFile(String pathName) {
Bitmap bitmap = null;
BitmapFactory.Options options = new BitmapFactory.Options();
for (options.inSampleSize = 1; options.inSampleSize <= 32; options.inSampleSize++) {
try {
bitmap = BitmapFactory.decodeFile(pathName, options);
Log.d(TAG_LOG, "Decoded successfully for sampleSize " + options.inSampleSize);
break;
} catch (OutOfMemoryError outOfMemoryError) {
// If an OutOfMemoryError occurred, we continue with for loop and next inSampleSize value
Log.e(TAG_LOG, "outOfMemoryError while reading file for sampleSize " + options.inSampleSize
+ " retrying with higher value");
}
}
return bitmap;
}

3) If you want to show a large image in small ImageView (eg thumnail), pass small sized bitmap to imageView instead of sending original bitmap and let android scale down automatically based upon UI params like scaleType/width/height.

Here is how you can get scaled down bitmap:

Bitmap bitmap = getResizedBitmap(bitmap, imageView.getWidth(), imageView.getHeight());

private static Bitmap getResizedBitmap(Bitmap bitmap, float maxWidth, float maxHeight) {

float width = bitmap.getWidth();
float height = bitmap.getHeight();
if (width > maxWidth) {
height = (maxWidth / width) * height;
width = maxWidth;
}
if (height > maxHeight) {
width = (maxHeight / height) * width;
height = maxHeight;
}
return Bitmap.createScaledBitmap(bitmap, (int) width, (int) height, true);

}

As you can see,  both the methods in  1 & 2,  try to decode bitmap and whenever face OOM, release resources and retry with increased options.inSampleSize. increment in inSampleSize decrease memory consumption by reducing image size and quality.

I have uploaded a demo project with both OOM prone and OOM proof code here for reference.

About rajawatshaill

A Programming junkie software Engineer
This entry was posted in Android and tagged , . Bookmark the permalink.

5 Responses to OutOfMemory (Due to large bitmap) Handling in Android

  1. Akhtar says:

    Thanks alot!!!! I was stuck for 2 days but your solution saved me. Thanks you so much!

  2. Daria says:

    Thank you!!!!!!!!!!!!!!!!! You are awesome!! I love you!!

  3. You really helped me! Use scaling of image, if OutOfMemory occures is great solution!

  4. Anonymous says:

    Nice Post

  5. fkdplc says:

    you dont need to use options.inSampleSize++ because as official docs say: Note: the decoder uses a final value based on powers of 2, any other value will be rounded down to the nearest power of 2.

Leave a comment