Scarce Commodities – Google Android, Memory, and Bitmaps

Working on mobile devices forces one to make conscious decisions regarding coding choices, if for no other reason that resources are scarce (memory, screen size, bandwidth). Taking the easy route and ignoring wise mobile programming practices can take what could be a promising application and make it a disappointing user experience.

If you’ve spent any time with the Google Android SDK, and have tried to read a JPEG into a Bitmap using Media.getBitmap, you’ve almost certainly run into this little gem of an error message:

bitmap size exceeds VM budget

Unfortunately, since Android caps all applications’ VMs at 16MB in size, it only takes one or two big image reads to get you into trouble, regardless of all the garbage collection and Bitmap recycles you may try (see code snippet at the end of this post for more on that).

So, what’s a programmer to do?

Well, the only thing one can do is to read only what you need into memory.  That means that you won’t be able to read in that 10MB jpeg sitting on your phone (at least, you won’t be able to read it reliably and / or repeatably) without trimming it down a bit.

The code below will do this for you; rather than calling Media.getBitmap, use this readBitmap function instead:

 

 

// Read bitmap
public Bitmap readBitmap(Uri selectedImage) {
Bitmap bm = null;
BitmapFactory.Options options = new BitmapFactory.Options();
options.inSampleSize = 5;
AssetFileDescriptor fileDescriptor =null;
try {
fileDescriptor = this.getContentResolver().openAssetFileDescriptor(selectedImage,”r”);
} catch (FileNotFoundException e) {
e.printStackTrace();
}
finally{
try {
bm = BitmapFactory.decodeFileDescriptor(fileDescriptor.getFileDescriptor(), null, options);
fileDescriptor.close();
} catch (IOException e) {
e.printStackTrace();
}
}
return bm;
}

 

The magic fairy dust in this function that allows you to trim down large bitmaps into digestible sizes is the options.inSampleSize property.  inSampleSize – in this instance – takes a bitmap and reduces its height and width to 20% (1/5) of its original size.  The larger the value of inSampleSize N (where N=5 in our example), the more the bitmap is reduced in size.

There’s also another coding practice that one should always use when dealing with Bitmaps in Android, and that is the use of the Bitmap recycle() method. The recycle() method frees up the memory associated with a bitmap’s pixels, and marks the bitmap as “dead”, meaning it will throw an exception if getPixels() or setPixels() is called, and will draw nothing.

In my projects, I have a helper function that does cleanup when I am finished using a Bitmap, named clearBitmap:

// Clear bitmap

public static void clearBitmap(Bitmap bm) {

bm.recycle();

System.gc();

}

 

Dealing with memory errors on Android apps seems to be the “problem child” issue that crops up the most (like too many threads on Blackberry apps – different post for a different day).

But like parenting a problem child, what’s called for is attention and intention to mitigate havoc wreaked.

About these ads
Tagged , , , , ,

12 thoughts on “Scarce Commodities – Google Android, Memory, and Bitmaps

  1. [...] — a very lucky night, I stumbled upon this post which I pulled a snippet of code from: In my projects, I have a helper function that does cleanup [...]

  2. John says:

    Thanks….This code is working….But what about the image quality ?
    That question remains always unanswered….Please if possible, give me solution over that…

    • davidjhinson says:

      If you want higher resolution images, drop the inSample number. 5 = 1/5 original size, 4=1/4 original image size, … 1=no resampling (original size).

      I only develop on Android, and I’m certainly not an Android apologist – though I seem to find myself explaining it’s shortcomings enough to be one.

      It is what it is – the trade off is always risking reading in a large enough image to blow up the heap, or sampling down the size to a safe enough size to keep your app from Force Closing.

  3. Juan says:

    What does the instruction
    bm = null
    accomplishes?
    It is a local variable and The method caller still has the original reference to the object. So it doesn’t help.
    The real deal is the call to recycle.

  4. Chooyan says:

    Hi,

    I am using drawable in XML file(like my imageswitcher) instead of using bitmap and I dont know how to implement it..Do you have the solution to the drawables? thanks!! (:

  5. David Junod says:

    You blindly resample by 5 regardless of the source size and the destination requirements. It would be more useful to see what the original size is before just arbitrarily sampling by 5.

    In your finally you reference a possible null value for fileDescriptor.

    In your cleanup routine the bm = null is totally useless.

  6. davidjhinson says:

    Edit: removed the bm=null, since it was a local as pointed out. Thank you, Juan and David.

  7. Pedro says:

    So this really doesn’t solve the problem, it will only delay it.

    options.inSampleSize = 5

    this will reduce the size and therefor take less memory, but wouldn’t it run out of memory eventually if you keep calling the function? Let’s say the app uploads photos to the server. Use this function to read the image, lower the quality, resize and send it away. So it will work for a while, but wouldn’t it run out after uploading a few?

  8. jimy says:

    Isn’t it possible to check the available heap size before trying to pull in a new image? If there is no enough free memory, simply skip the actual image.

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

Follow

Get every new post delivered to your Inbox.

Join 7,249 other followers

%d bloggers like this: