Sunday, November 20, 2011

'An error has occurred' when working with Bitmaps

On a recent project I needed to rotate and slice images taken from the camera, and I found that I was getting regular, but annoying to track down 'an error has occurred' messages.

I couldn't see anything in particular that was wrong with my code, and what made it worse was that I wasn't receiving any errors at all in the emulator, only when I deployed the app to my phone for testing.

It took a few hours to figure out what was going on, so I thought I'd share it here and maybe save somebody else some time.

Like a lot of errors, it seemed painfully obvious after the fact, but the cause was I was basically running out of memory when creating the bitmap objects below. From my experience, you can only create one or two bitmap objects before you will encounter issues like this, because the heap size on Android devices is limited to something like 16 MB on a G1 and 24 MB on a Nexus one.
.. That's not a lot of 6 MB photos.

Luckily, it's super easy to fix.
All you need to do is recycle the bitmaps once you've finished with them, as per below code, and as pointed out by Romain Guy here,

"..The problem is that it can take a couple of GC cycles for a Bitmap to be properly released on Android before Android 3.x. Even if you call recycle() I believe the bitmap counts against your heap usage until at least the next GC. This is one of the very few situations where I would advise you to force a GC by calling System.gc()."

Matrix mat = new Matrix();

Bitmap photoRotated = Bitmap.createBitmap(bitmapToSave, 0, 0, bitmapToSave.getWidth(), bitmapToSave.getHeight(), mat, false);

Bitmap photoCut1 = Bitmap.createBitmap(photoRotated, 0, 0, photoRotated.getWidth(), heightOfSlice);


//save photoCut1 bitmap here


So don't forget to recycle and call System.gc() a couple of times when working with large files like images and hopefully, like me, your errors messages will disappear.