I'm writing a camera app and when I take a picture, I receive a byte [], decode it into a Bitmap and rotate it before saving it to JPEG. I'm rotating the photo using a native library, however the bitmap is still decoded from a byte[] into memory for this (still, allows me to keep 1 Bitmap instead of 2). So essentially there's 1 place in my code where I require a lot of memory and OOM on some devices where heap is low and cameras are stupid-megapixels. Any suggestions how to fix this without on loosing image quality?
I don't think I want to use largeHeap="true"
Should I forget about rotation and just set EXIF?
Also I'm not so keen on trying to 'predict' if I will OOM as the math's not adding up: Android OutOfMemory when GC reports free memory?
Any suggestions how to fix this without on loosing image quality?
Use android:largeHeap="true"
.
Or, use some other native library that allows you to hand over the byte[]
and does the rotation and saving to disk for you, to avoid the Bitmap
and any Java-level processing of the huge thing.
Or, if your minSdkVersion
is 19, and the rest of your logic supports it, use inBitmap
on BitmapFactory.Options
to try to reuse an already-allocated Bitmap
object rather than allocate a fresh one. This option is available on earlier versions of Android, but for those it has to be an exact match in terms of resolution; on 19+, the Bitmap
to be reused just has to be big enough to handle what you are trying to load into it.
I don't think I want to use largeHeap="true"
It may not help (not all devices will give you a larger heap), and there are costs to the user for the larger heap limit. That being said, manipulating big camera images is difficult without more memory, whether that is in the Java heap or represents allocations from the OS from native code.
Should I forget about rotation and just set EXIF?
That's certainly another possibility, though various things, like ImageView
, seem to ignore EXIF headers.
I'm not so keen on trying to 'predict' if I will OOM as the math's not adding up
In part, that's because Dalvik does not have a compacting/moving GC, and ART only has one while your app is not in the foreground. OutOfMemoryError
means that there is no single contiguous free block of memory for what you are trying to allocate.
You might not have enough memory to create a rotated copy of a large bitmap.
You could instead paint a rotated image of the original.
Furthermore there are things that need to be considered when processing images:
- Always load images scaled to the size of the ImageView.
- Always recycle your images
- Consider using largeHeap=true if you still have issues. Android might be growing the heap size too slowly (see https://stackoverflow.com/a/14462026/1390015).