How to solve OOM issue in android . I have tried almost every things like scaling bitmap,inPurgeable in BitmapOption,releasing all resources etc. but still getting OOM issue.
This is basically in images taken by camera or any image i.e. larger then 1.5 mb. I have also images 15-20 mb size in my app.
this is what i´m doing to avoid OOM errors, Using some of the code of the android training. This is in my class "ScaledFactor"
public static Bitmap decodeSampledBitmapFromResource(Resources res, int resId,
int reqWidth, int reqHeight) {
// First decode with inJustDecodeBounds=true to check dimensions
final BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
BitmapFactory.decodeResource(res, resId, options);
options.inPurgeable = true; // I aded this to the android training code, without this I still have OOM errors. so try using inPurgeable = true
// Calculate inSampleSize
options.inSampleSize = calculateInSampleSize(options, reqWidth, reqHeight);
// Decode bitmap with inSampleSize set
options.inJustDecodeBounds = false;
return BitmapFactory.decodeResource(res, resId, options);
}
In my Activity I use
background = ScaledFactor.decodeSampledBitmapFromResource(getResources(), R.drawable.menu, screenheight, screenwidth); // screeenhieght is the output height , screenwidth is the output width
Then in the on destroy method, or after calling an other intent I use background.recycle();
I´m not using the hdpi, ldpi and so folders... I just use the drawable with large bitmaps, and do the scalling. this way you save some mb on the final apk file
The android training code is here for more info http://developer.android.com/training/displaying-bitmaps/load-bitmap.html#load-bitmap
C ya ! Hope this helps, I spent a hole day trying to figure this out and reading all the questions and answers in this forum. This is just the example of the background image but i have more than 20 images in my game all loaded this way but with smaller output size, and it works very smooth.
Have you tried Bitmap.recycle(); ?
It once solved my Out of Memory issue.
Related
I have a project on Android and iOS, there is a section where it shows a 360 view of a car, in iOS I just get the 60 images from internal storage that were previously downloaded from the internet, and these images are showed when the user starts to swipe the car to the right or to the left. And this process takes just 200ms to be ready to interact with the user.
But in Android I have to take first the 60 images and convert them in bitmaps, and then the process is similar to the iOS process. Nevertheless, this first process, convert all of them to bitmap takes about 3 seconds o more. I have read the process to show an image in Android in many sources of information and seems like is necessary use a bitmap for this task, so is possible to reduce the time to get all bitmaps?, or could I save a bitmap to avoid converting the PNG file again to a new bitmap when the users open the same view again?
The code that I'm using to convert png file to a bitmap object is the same that Android developers documentation recommend:
https://developer.android.com/topic/performance/graphics/load-bitmap
My source code for get bitmap is:
public static Bitmap decodeSampledBitmapFromFile(String filePath, int reqWidth, int reqHeight) {
// First decode with inJustDecodeBounds=true to check dimensions
final BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
BitmapFactory.decodeFile(filePath, options);
options.inSampleSize = 1;
// Decode bitmap with inSampleSize set
options.inJustDecodeBounds = false;
Bitmap bitmap =BitmapFactory.decodeFile(filePath, options);
Log.d("img360","bitmap res "+bitmap.getWidth()+ " h "+bitmap.getHeight());
return bitmap;
}
I'm really thankful for your help and support.
If you want to download images from Internet and display them on android
Just put an imageview and use picaso or glide library
It is faster and easier
I am creating a bitmap and it takes about 11 mb in the heap , though it is of the small size. Well I wanted to know if I can create the bitmap and also sclae it as a same time. The reason I want to do it is , the memory allocation , as If I understand correctly from different bitmap questions which are posted here , and that is
The bitmap allocates the memory as when it is created
So if its , then scaling it again take some process time and also increase the heap size until and unless the garbage collection is not occurred
So what I am doing is
screenHeight = displaymetrics.heightPixels;
screenWidth = displaymetrics.widthPixels;
float aspectRatio = screenWidth / screenHeight;
int modifiedScreenHeight = 400;
int modifiedScreenWidth = (int) (modifiedScreenHeight * aspectRatio);
mBitmap = Bitmap.createBitmap(modifiedScreenWidth, modifiedScreenHeight, Bitmap.Config.ARGB_8888);
So now it is creating the bitmap and allocation the memory , by memory analyzer tool in android studio I can see that it took 11mb in memory.
But I want to minimize them ,I have visited a link and I want to do some more scaling by options as show in this video . but it uses the file to decode such as
BitmapFactory.decodeFile(??,options);
where as I have no file to decode from , I want to decode it from the bitmap I created and to wash away the last created bitmap to clear the memory.
Or if it is possible to set the options when creating it so that we can avoid from extra memory allocation .
Please help.
You can use this using BitmapFactory.Options - specifically, use the options to decode the width / height of the bitmap, then sampleSize to determine how large the generated bitmap will be.
According to your example, you'd like the width/height of the bitmap to be 400 by 400 * aspectRatio. So, first, you'll need to see how large the bitmap needs to be. Do this as so:
BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
BitmapFactory.decodeFile(??, options);
int bitmapWidth = options.outWidth;
int bitmapHeight = options.outHeight;
This action will only decode the bitmaps size, without actually allocating memory for the bitmap's pixels. This is good because it's a very quick and light operation which doesn't require much resources and helps you make a more educated decision when loading the bitmap. Now we must use these size to determine how big the generated bitmap will be.
int sampleSize = 1;
while (bitmapWidth / sampleSize > 400 && bitmapHieght / sampleSize > 400 * aspectRatio)
sampleSize *= 2;
sampleSize must be a power of 2 for this to work, and what it will do is determine how many pixels to "skip" when reading the bitmap into memory. This algorithm will set a sample size to a size equal to 1st sample size which will produce a bitmap immediately smaller than the required bounds. You can tweak this if you'd like a slightly different implementation.
Now that you have the sample size, set it with in the options object and load the actual bitmap:
options.inJustDecodeBounds = false;
options.inSampleSize = sampleSize;
Bitmap bitmap = BitmapFactory.decodeFile(??, options);
The generated bitmap will be smaller than the required bounds, thus limiting your memory requirements for creating the bitmap object.
Hope this helps.
I'm new to android and am working on my first real app so i apologize if this question has been answered, or isn't detailed enough. I'm having the common OutOfMemoryError when loading bitmaps to my android app. I've searched around on stackoverflow and went through the google tutorial that describes how to use InSampleSize to reduce the memory for each bitmap.
When testing out the app to see how much memory I was saving by down scaling my bitmaps I noticed that the heap size was still growing at the same rate. I.E. When I use an InSampleSize = 8 vs not scaling the bitmap at all (or InSampleSize = 1) the heap grows the same for each.
I have tried printing the byteCount with:
myImage.getByteCount()
for both of the scaling SampleSizes listed above and they both have identical ByteCounts. Is this the expected behavior? Shouldn't the byte count be reduced since I'm downscaling images?
I was expecting to see the memory used to the bitmap reduced by a factor of 8 or so. Am I missing something, or is my understanding of image scaling incorrect? Thanks.
edit: After doing some testing I discovered that if I used createScaledBitmap the memory was reduced but it required me first inflating the original Bitmap then scaling. I'm assuming this is non-ideal since it requires that. I thought the first method would do this for me but according to my heap dumps it isn't.
Initial Code and heap dump:
private static Bitmap decodeSampledBitmap(Resources res, int resId, int width, int height
{
// First decode with inJustDecodeBounds=true to check dimensions
final BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
options.inPreferredConfig = Config.ARGB_8888;
BitmapFactory.decodeResource(res, resId, options);
// Calculate inSampleSize
options.inSampleSize = calculateInSampleSize(options, width, height);
// Decode bitmap with inSampleSize set
options.inJustDecodeBounds = false;
return BitmapFactory.decodeResource(res, resId, options);
}
Updated code (same as above with the only difference being) and heap dump:
private static Bitmap decodeSampledBitmap(Resource res, int ResId, int width, int height)
{
....
Bitmap bitmap = BitmapFactory.decodeResource(res, resId, options);
return Bitmap.createScaledBitmap(bitmap, options.outWidth/options.inSampleSize, options.outHeight/options.inSampleSize, false);
}
It won't let me post images due to my reputation but according to heap dump it is using 79.155MB. Using the second technique the heap dump is using 26.912 MB.
Are you scaling the Bitmap after decoding it using InSampleSize?
I have a question that I seem to find the answer nowhere.
Does this lines of code:
final BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
BitmapFactory.decodeStream(is, null, options);
actually mean that, that file is being downloaded? Android docs say something like this:
decode with inJustDecodeBounds=true to check dimensions
and
Does:
options.inSampleSize = calculateInSampleSize(options, reqWidth,
reqHeight);
// Decode bitmap with inSampleSize set
options.inJustDecodeBounds = false;
BitmapFactory.decodeStream(is, null, options);
means that it will actually download the file smaller (not downloaded as original size and copied after that to a smaller size bitmap).
Clear example: I have some url's that point to many 2000 x 1500 images. By decoding those files and loading them to bitmaps, do I need to have enough memory for downloading the file at its full resolution (2000 x 1500), if I only need thumbnails of (200 x 150)?
I know another answer has already been accepted as the right one but for clarity...
This line options.inJustDecodeBounds = true; means that the call to BitmapFactory.decodeStream(is, null, options); doesn't get the bitmap information but does get bounding information and the MimeType.
You can then use these returned values, outWidth, outHeight and outMimeType to get a 'resampled' version of the bitmap data by setting options.inJustDecodeBounds = false; and setting the sample size to a given ratio determined by your desired output dimensions options. inSampleSize = [int].
See this very informative page for more information: Loading Large Bitmaps Efficiently
Indeed looks like the file is being downloaded, and the effiency part comes where the bitmap being loaded in memory is the smaller one ( the one being decoded with inSampleSize options).
I'm developing an Android app which uses multiple large images in several of its activities. Each image is around 1280x800 and I load about 2-4 of these images for each Activity. I realize that these images are very large in terms of the memory that is allocated to each individual app on a device, but how can I display them at their original resolution without running into a java.lang.OutOfMemory error? I need these images to be displayed at their full size on a screen (scaling is done automatically by xml when the screen is smaller than the image). I saw several solutions involving shrinking down images into thumbnails and storing those into memory, but wouldn't that cause the image to lose it's original size/resolution? Thanks for your help!
There are a few things you can do about this.
The first thing that comes to mind is that 1280x800 is (probably) your entire screen, so you should only need to display one at a time. Don't hold the others in memory while you do that.
Still a 1280x800 image at 4 bytes per pixel is only 4MB, and tablets seem to all offer 48MB of heap these days. You should be able to hold a few in memory if you need to. If you're running out of memory, it's possible you're leaking. If you watch in DDMS, does your memory usage continue to grow as you change activities?
A common source of leaks is the bitmaps themselves. Be sure to call Bitmap#recycle when you're done with them.
If it really comes down to it, and you cannot fit into the heap space provided, you can also try adding android:largeHeap="true" to the application tag in your manifest. This will request the system offer you more heap space - up to 256MB on some devices. This should be a last resort, though, as it will vary by device, and be completely ignored on some (the original Kindle Fire comes to mind).
You can see just how much total heap space you have with Runtime.getRuntime().maxMemory();. See this answer for a more detailed explanation. It's trickier to see just how much you're using, but there is a description here if you want to tackle that beast.
Finally, there may be a better way to load your images than specifying them in xml. Be sure to read this developer guide page. Even if you must leave them in xml, I have seen marked improvement in memory usage by splitting the image assets into the drawable-hdpi, drawable-mdpi, etc. directories rather than just dumping them in drawable.
This article describes pretty well how to create a heap dump and analyze it using Eclipse MAT. This will help you find the most likely suspects for memory leaks pretty quickly.
Again I point you to this great link I found from another SO Question that has tutorials of how to properly over come the problem.
Image needs to scaled before loading the image using BitmapFactory or related methods.
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) {
if (width > height) {
inSampleSize = Math.round((float)height / (float)reqHeight);
} else {
inSampleSize = Math.round((float)width / (float)reqWidth);
}
}
return inSampleSize;
}
public static Bitmap decodeSampledBitmapFromResource(Resources res, int resId,
int reqWidth, int reqHeight) {
// First decode with inJustDecodeBounds=true to check dimensions
final BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
BitmapFactory.decodeResource(res, resId, options);
// Calculate inSampleSize
options.inSampleSize = calculateInSampleSize(options, reqWidth, reqHeight);
// Decode bitmap with inSampleSize set
options.inJustDecodeBounds = false;
return BitmapFactory.decodeResource(res, resId, options);
}
whole thing is explained in Android developer site, Loading Large Bitmaps Efficiently