Android OutOfMemory Error while loading Bitmaps - android

In Application i need to load a few Bitmaps on create.
To save Memory i'm loading one image, rescale it by creating a scaledBitmap out of it, recycle the unscaled Bitmap on so on:
bmpUnscaled = BitmapFactory.decodeResource(getResources(), R.drawable.cultivation_plant_resized_1);
plant1 = Bitmap.createScaledBitmap(bmpUnscaled,(int) plant[0].getWidth(), (int) plant[0].getHeight(), true);
bmpUnscaled.recycle();
System.gc();
bmpUnscaled = BitmapFactory.decodeResource(getResources(), R.drawable.cultivation_plant_resized_2);
plant2 = Bitmap.createScaledBitmap(bmpUnscaled,(int) plant[0].getWidth(), (int) plant[0].getHeight(), true);
bmpUnscaled.recycle();
System.gc();
and so on...
I am doing this 10 Images, wich are scaled relative to the screen resolution.
The orginal Image is a PNG (570x900 (max. 660KB))
Does anybody have some Ideas to save Memory simply?
I'm desperate right now...

Have you read: http://developer.android.com/training/displaying-bitmaps/load-bitmap.html?
The article contain great information about working with BitMap.

Related

Loading and cropping bitmaps without Out Of Memory exception

I need to crop images from Facebook, Instagram or the device itself. At the end of the user flow (where he selects them), all the said images should be send to the server. But all in the same width/height ratio (e.g. 3/2), therefore I need to crop the images manually.
Here a simple example of what's going on in my upload service and the cropping:
Bitmap bitmap = ImageLoading.getLoader(UploadService.this).loadImageSync(path);
//crop calculations
Bitmap croppedBitmap = Bitmap.createBitmap(bitmap, x, y, w, y);
String croppedPath = saveCroppedImage(croppedBitmap);
I then read this file from the filesystem and encode it to BASE64 to send it to the backend.
When I have to do this for multiple images, I regularly get an OOM Exception. Maybe I'm going at this the wrong way.. Cropping on the server side is really the last thing I want to do, because then the backend would have to query Facebook or Instagram.
Loading a scaled version of the bitmap isn't an option, I'm not displaying it on the device.
I have tried:
System.gc()
Bitmap.recycle();
Should I really use largeHeap in my manifest?
note: I'm using Universal Image Loader for the user flow as well, that's why I'm using it in the upload service too.
I think you should add largeHeap = true in the AndroidManifest file.
Secondly, If you are using Universal ImageLoader, you can download the bitmap in smaller size. Please have a look at this code:
ImageSize targetSize = new ImageSize(80, 50); // result Bitmap will be fit to this size
Bitmap bmp = imageLoader.loadImageSync(imageUri, targetSize, options); // This bitmap will be of specified size.
You can further read about Universal Image Loader by following the link.

how to reduce chace on android application (using eclipse)?

I'm developing application for my android tablet that using many images.
in my activity, I use effect splash that show image (3840 x 2108 70 KB) for the opening theme.
I use another background image (3840 x 2108 69 KB).
but, when I test it on my tablet, this application's cache reached 80 MB!
For your information, I load the image from my xml file.
Can anyone help me to reduce it?
Is it wrong to load image from xml file?
Is it the size of my images that cause this problem?
//UPDATE
at the end, i didn't found a really good way to my question. I'm using xml (I put at dawable) file to replace my big size image, and this method really reduce the cache alot. My conclusion is avoid using big image, instead, just replace the color image using color.
The advantage to use color is "faste to load", it reduce lag of my application.
Android default color model is ARGB_8888. It takes 4 byte for 1 pixel. So splash and background bitmap images in memory takes 3840*2108*4*2 = 61.76MB. You could resize the images for different device dpi and put them in proper drawable folder. For example, drawable-hdpi is suitable for 240 dpi, drawable-xxhdpi is suitable for 480 dpi.
In addition, you could manually load the images with java code. The following is a method to resolve the image safely:
protected Bitmap getBitmapSafely(Resources res, int id, int sampleSize) {
// res = youractivity.getResources, id = R.drawable.yourimageid
Bitmap bitmap = null;
BitmapFactory.Options options = new BitmapFactory.Options();
options.inPurgeable = true;
options.inSampleSize = sampleSize;
try {
bitmap = BitmapFactory.decodeResource(res,
id, options);
} catch (OutOfMemoryError oom) {
Log.w("ImageView", "OOM with sampleSize " + sampleSize, oom);
System.gc();
bitmap = getBitmapSafely(res, id, sampleSize + 1);
}
return bitmap;
}
Your could use this method with sampleSize = 1 at first time. If there is not enough memory, it will catch OOM and increase the sampleSize until the image can be resolved.

90MB heap size when loading drawables

I want to show a preview of some images from the users device. For this purpose I search the external storage for image files and for every folder which contains some, I list the folder's name and an image from this folder in a listview.
On my Nexus there are 6 folders containing images, so I have 6 listview items.
I load all images using:
Drawable.createFromPath(file.getAbsolutePath())
And cache the resulting drawable in a HashMap in order to prevent loading the same image multiple times.
However, the heap is growing from 20MB to >90MB. When the images are loaded the app response is delayed like 2 seconds. Pretty bad.
I have no idea how the heap can grow to 90MB from 6 images which are like 50KB but whatever. To fix this I tried to load subsampled bitmaps from the images - however whenever I load them I get an outofmemory exception.
I have verified multiple times that not more than those 6 images are loaded.
What can I do?
What you should do is analyze your app's memory usage using MAT tool, as described in this amazing article. This tool will help you identify potential memory leaks and see what exactly triggers the heap growth.
I have used the tool what Egor described and there were no memory leaks. The images took about 30MB heap. This amount can only be reduced by reducing the image size. My solution uses subsampling and takes about 3MB heap now.
private Drawable loadDrawable(Context context, File file) {
Drawable drawable = drawables.get(file);
if (drawable == null) {
final int targetSize = 500;
// get subsampling factor
Options opts = new Options();
opts.inJustDecodeBounds = true;
BitmapFactory.decodeFile(file.getAbsolutePath(), opts);
int largest = opts.outWidth > opts.outHeight ? opts.outWidth : opts.outHeight;
float factor = largest / (float) targetSize;
factor = Math.round(factor);
// load bitmap with subsampling
opts = new Options();
opts.inSampleSize = (int) factor;
Bitmap bitmap = BitmapFactory.decodeFile(file.getAbsolutePath(), opts);
drawable = new BitmapDrawable(getResources(), bitmap);
drawables.put(file, drawable);
}
return drawable;
}

Merging image from camera with image from drawables

I´m trying to merge 2 images, one is bitmap from camera, second one is .png file stored in drawables. What I did was that I used both images as bitmaps and I tried to merge them by using canvas, something like this:
Bitmap topImage = BitmapFactory.decodeFile("gui.png");
Bitmap bottomImage = BitmapFactory.decodeByteArray(arg0, 0, arg0.length);
Canvas canvas = new Canvas(bottomImage);
canvas.drawBitmap(topImage, 0, 0, null);
But I keep getting "Bitmap size exceeds VM budget" error all the time. I tried nearly everything, but still, it keeps throwing this error. Is there another way of merging 2 images? What i need to do is simple - I need to take photo and save it merged with that .PNG image stored in drawables. For example this app is very close to what i need - https://play.google.com/store/apps/details?id=com.hl2.hud&feature=search_result#?t=W251bGwsMSwyLDEsImNvbS5obDIuaHVkIl0.
Thanks :)
See the below code for combining two images.
This method returns combined bitmap
public Bitmap combineImages(Bitmap frame, Bitmap image) {
Bitmap cs = null;
Bitmap rs = null;
rs = Bitmap.createScaledBitmap(frame, image.getWidth() + 50,
image.getHeight() + 50, true);
cs = Bitmap.createBitmap(rs.getWidth(), rs.getHeight(),
Bitmap.Config.RGB_565);
Canvas comboImage = new Canvas(cs);
comboImage.drawBitmap(image, 25, 25, null);
comboImage.drawBitmap(rs, 0, 0, null);
if (rs != null) {
rs.recycle();
rs = null;
}
Runtime.getRuntime().gc();
return cs;
}
You can change height and width as per your requirements
Hope this will help...
How large are the images? I've only encountered this problem when trying to load large images into memory.
Is the byte array your decoding actually an image?
From a quick look at the android docs you can capture an image using the default camera app which may work in this situation.
http://developer.android.com/training/camera/photobasics.html
Also see this question: Capture Image from Camera and Display in Activity
Edit: You may also need to scale the image from the camera down if it is very large. See the end of the android page I linked to for details on that.

ViewFlipper : Bitmap size exceeds VM budget

I am using a ViewFlipper to show some images from db.
I am taking the blob values to an ArrayList then, converting each byte array to bitmap.
And then I am setting these each bitmap to each Imageview of ViewFlipper.
If the count of images is below 10, then it is working fine. But if it exceeds 10, then suddently it caught an Exception :
OutOfMemoryException : Bitmap size exceeds VM budget.
When I use inSampleSize of BitmapFactory.Options, it is working fine.But I want to display the image with actual height and width. How can I do this without exception?
My code is :
ViewFlipper vfImage = (ViewFlipper)findViewById(R.id.vfImage);
for(Photos objPhotos :arPhotos)
{
byte[] btImages = null;
Bitmap bitmapImage = null;
btImages = objPhotos.getImage();
ImageView imgPhoto= new ImageView(this);
bitmapImage = BitmapFactory.decodeByteArray(btImages, 0, btImages.length);
imgPhoto.setImageBitmap(bitmapImage);
vfImage.addView(imgPhoto);
}
vfImage.startFlipping();
Please help me..
Thank you...
You should think about unloading the bitmaps that are currently not shown, to keep in memory only those that are on the screen right now. Good luck!
Once you have completed using your bitmaps, try and make it null like this,
Bitmap bitmapImage = null;
Try adding the above line in the last line of your for loop. This means each and every time the bitmap is made null, which reduces the memory being captured by your bitmap. Also try providing
bitmapImage.recycle();
This will recycle the bitmap and provide you with free memory.
Also you can refer to my question here

Categories

Resources