OutOfMemory (Due to large bitmap) Handling in Android

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

I am assuming that you are already using other memory optimizations techniques 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.

Advertisements

About rajawatshaill

A Programming junkie software Engineer
This entry was posted in Uncategorized. Bookmark the permalink.

One Response 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!

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s