I have read many related posts concerning memory allocation problems with decoding bitmaps, but am still unable to find the solution to the following problem even after using the code provided in the official website.
Here is my code:
public static Bitmap decodeSampledBitmapFromResource(InputStream inputStream, int reqWidth, int reqHeight) {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
byte[] buffer = new byte[1024];
int len;
try {
while ((len = inputStream.read(buffer)) > -1) {
baos.write(buffer, 0, len);
}
baos.flush();
InputStream is1 = new ByteArrayInputStream(baos.toByteArray());
InputStream is2 = new ByteArrayInputStream(baos.toByteArray());
final BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
BitmapFactory.decodeStream(is1, null, options);
options.inSampleSize = calculateInSampleSize(options, reqWidth, reqHeight);
options.inPurgeable = true;
options.inInputShareable = true;
options.inJustDecodeBounds = false;
options.inPreferredConfig = Bitmap.Config.ARGB_8888;
return BitmapFactory.decodeStream(is2, null, options);
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
public static int calculateInSampleSize(BitmapFactory.Options options, int reqWidth, int reqHeight) {
// Raw height and width of image
final int height = options.outHeight;
final int width = options.outWidth;
int inSampleSize = 1;
if (height > reqHeight || width > reqWidth) {
// Calculate ratios of height and width to requested height and width
final int heightRatio = Math.round((float) height / (float) reqHeight);
final int widthRatio = Math.round((float) width / (float) reqWidth);
// Choose the smallest ratio as inSampleSize value, this will guarantee
// a final image with both dimensions larger than or equal to the
// requested height and width.
inSampleSize = heightRatio < widthRatio ? heightRatio : widthRatio;
}
return inSampleSize;
}
bitmap = decodeSampledBitmapFromResource(inputStream, 600, 600);
I am getting "Out of memory error on a 3250016 - byte allocation" in this line:
return BitmapFactory.decodeStream(is2, null, options);
It would seem to me that 3.2 MB is small enough to be allocated. Where am I going wrong? How can I solve this?
EDIT
After looking into this solution HERE by N-Joy it works fine with Required size 300 but my required size is 800, so i am still getting the error.
The method
decodeSampledBitmapFromResource
is not memory efficient because it uses 3 streams: the ByteArrayOutputStream baos, ByteArrayInputStream is1 and ByteArrayInputStream is2, each of those stores the same stream data of the image (one byte array for each).And when I test with my device (LG nexus 4) to decode an 2560x1600 image on SDcard to target size 800 it takes something like this:
We can see: too much memory allocated (28.5 MB) just to decode 4096000 a pixel image.
Solution: we read the InputStream and store the data directly into one byte array and use this byte array for the rest work.
Sample code:
The method that does the calculation:
And the result:
Have a look at this video. http://www.youtube.com/watch?v=_CruQY55HOk. Do not use system.gc() as suggested in the video. Use a MAT Analyzer to find out memory leaks. The returned bitmap is too huge causing memory leak i guess.
ARGB_8888
uses more memory as it takes Alpha color value so my suggestion is to useRGB_565
as stated HERENote: Quality will be little low compared to
ARGB_8888
.i also had same problem earlier.. and i have managed it by using this function where you can get scale as your required width and height.
and refer Memory Leak Error Android and error in loading images to gridview android
Out of memory problems when decoding bitmaps are not often linked with the image size you are decoding. Of course if you try to open an image 5000x5000px you will fail with a OutOfMemoryError, but with the size of 800x800px it is totally reasonable and should work fine.
If your device is out of memory with a 3.2 MB image it's likely because you are leaking context somewhere in the app.
It's the first part of this post:
What it means it's that you are using Activity Context in components that should not, preventing them to be garbage collected. Because there components often are held by activities, those activities are not GC and your java heap will grow very fast and your app will crash at one time or another.
As Raghunandan said, you will have to use MAT to find wich Activity/Component is held and remove the context leak.
The best way I found for now to detect context leak is orientation change. For example, rotate your ActivityMain multiple times, run MAT and check if you have only one instance of ActivityMain. If you have multiple ones (as much as rotation changes) it means there is a context leak.
I found years ago a good tutorial on using MAT. Maybe there is better one now.
Other posts on memory leaks:
Android - memory leak or?
Out of memory error on android emulator, but not on device
You're probably holding on to previous bitmap references. I'm guessing that you're executing this code several times and never executing
bitmap.recycle()
. Memory will inevitably run out.