Android Snippet – OutOfMemoryError: Bitmap size exceeds VM budget in Android

Android Snippet – OutOfMemoryError: Bitmap size exceeds VM budget in Android

We are going to learn one way of fixing OutOfMemoryError: Bitmap size exceeds VM budget in Android. This error occurs when you try to load an image in excess of the available allocated memory for your app.

If you have tried to load a huge bitmap image (16 or above MB)in your android application, there is a possibility that you will experience this kind of error.

There are many ways to solve this issue but we are going to learn how we can solve it by loading a scaled down version of the bitmap into Memory

For a detail discussion about other option available in solving this memory error in android visit the android user guide.

“For example, it’s not worth loading a 1024×768 pixel image into memory if it will eventually be displayed in a 128×96 pixel thumbnail in an ImageView.

To tell the decoder to subsample the image, loading a smaller version into memory, set inSampleSize to true in your BitmapFactory.Options object. For example, an image with resolution 2048×1536 that is decoded with an inSampleSize of 4 produces a bitmap of approximately 512×384. Loading this into memory uses 0.75MB rather than 12MB for the full image (assuming a bitmap configuration of ARGB_8888). Here’s a method to calculate a sample size value that is a power of two based on a target width and height.1”

Before we start, the first thing I will do is to list the environment and tools I used in this android code snippet but feel free to use whatever environment or tools you are familiar with.

Windows 7

Android Studio

Samsung Galaxy Fame Lite

Min SDK 14

Target SDK 19

To create a new android application project, following the steps as stipulated below.

Go to File menu

Click on New menu

Click on Android Application

Enter Project name: OutOfMemoryError

Package: com.inducesmile.outofmemoryerror

Keep other default selections.

Continue to click on next button until Finish button is active, then click on Finish Button

Once you are done with creating your project, copy and paste the following code snippet to your project. Replace the code in your MainActivity.java file with the following code.

Make sure you change the package name if you did not use the same package.

package outofmemoryerror.inducesmile.com.outofmemoryerror;

import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.Bundle;
import android.support.v7.app.ActionBarActivity;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.Button;
import android.widget.ImageView;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;

public class MainActivity extends ActionBarActivity {

private ImageView displayImage;

private final int IMAGE_MAX_SIZE = 200;

@Override

protected void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

setContentView(R.layout.activity_main);

displayImage = (ImageView)findViewById(R.id.large_image);

Button oldButton = (Button)findViewById(R.id.old_image);

Button newButton = (Button)findViewById(R.id.new_image);

oldButton.setOnClickListener(new View.OnClickListener() {

@Override

public void onClick(View v) {

displayImage.setImageResource(R.drawable.drops);

}

});

newButton.setOnClickListener(new View.OnClickListener() {

@Override

public void onClick(View v) {

File file = new File("Path-to-your-image-file");

Bitmap sampledImage = sampleFile(file);

displayImage.setImageBitmap(sampledImage);

}

});

}

@Override

public boolean onCreateOptionsMenu(Menu menu) {

// Inflate the menu; this adds items to the action bar if it is present.

getMenuInflater().inflate(R.menu.menu_main, menu);

return true;

}

@Override

public boolean onOptionsItemSelected(MenuItem item) {

// Handle action bar item clicks here. The action bar will

// automatically handle clicks on the Home/Up button, so long

// as you specify a parent activity in AndroidManifest.xml.

int id = item.getItemId();

//noinspection SimplifiableIfStatement

if (id == R.id.action_settings) {

return true;

}

return super.onOptionsItemSelected(item);

}

private Bitmap sampleFile(File f){

Bitmap b = null;

//Decode image size

BitmapFactory.Options o = new BitmapFactory.Options();

o.inJustDecodeBounds = true;

FileInputStream fis = null;

try {

fis = new FileInputStream(f);

BitmapFactory.decodeStream(fis, null, o);

} catch (FileNotFoundException e) {

e.printStackTrace();

}finally {

try {

fis.close();

} catch (IOException e) {

e.printStackTrace();

}

}

int scale = 1;

if (o.outHeight > IMAGE_MAX_SIZE || o.outWidth > IMAGE_MAX_SIZE) {

scale = (int)Math.pow(2, (int) Math.ceil(Math.log(IMAGE_MAX_SIZE /

(double) Math.max(o.outHeight, o.outWidth)) / Math.log(0.5)));

}

//Decode with inSampleSize

BitmapFactory.Options o2 = new BitmapFactory.Options();

o2.inSampleSize = scale;

try {

fis = new FileInputStream(f);

b = BitmapFactory.decodeStream(fis, null, o2);

} catch (FileNotFoundException e) {

e.printStackTrace();

}finally {

try {

fis.close();

} catch (IOException e) {

e.printStackTrace();
}
}
return b;
}
}

The activity_main.xml file content is shown below.

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"

xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent"

android:layout_height="match_parent" android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
android:paddingBottom="@dimen/activity_vertical_margin" tools:context=".MainActivity">

<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/original_image"
android:id="@+id/old_image"
android:layout_alignParentTop="true"
android:layout_centerHorizontal="true"
android:layout_marginTop="20dp" />

<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/sample_image"
android:id="@+id/new_image"
android:layout_below="@+id/old_image"
android:layout_alignLeft="@+id/old_image"
android:layout_marginTop="10dp"
android:layout_alignStart="@+id/old_image" />

<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/large_image"
android:layout_below="@+id/new_image"
android:layout_centerHorizontal="true"
android:layout_marginTop="30dp" />

</RelativeLayout>

We create two button. The first button is used to load the original image with size 19 MB to an ImageView. Once you click on the button, it will throw OutOfMemoryError exception. This is to let you understand more about this error before will fix it.

The second button is used to display a sample or smaller sized of the same image to our ImageView. With this, our image is loaded perfectly well with crashing our application. You can change the image path in the sample code provided in this android code snippet.

Save the file and run your project.

You can download the code for this tutorial below. If you are having hard time downloading the tutorials, kindly contact and I will send it to you.

Remember to subscribe with your email so that you will be among the first to receive our new post once it is published

Add a Comment