I am trying to implement the code below converting a image path into a bitmap to display on my activity. I am getting the below error. I have tried a bunch of different solutions but none are working
Strange out of memory issue while loading an image to a Bitmap object
Android: Resize a large bitmap file to scaled output file
OutOfMemoryError: bitmap size exceeds VM budget :- Android
Error:
E/dalvikvm-heap(19252): 12742656-byte external allocation too large for this process.
for(int i = 0; i < numItems; i++) {
File imgFile = new File(photoPaths.get(i));
if(imgFile.exists())
{
images[i] = BitmapFactory.decodeFile(imgFile.getAbsolutePath());
}
You may consider loading them in a more just-in-time kind of approach, or using the inSampleSize option of the bitmap factory (i.e., you'd pass a BitmapFactory.Options in to the factory with inSampleSize set to, ideally, a power of 2). Also make sure you set inPurgeable true.
In the event that you are pulling these images from the MediaStore's ContentProvider, you can also use thumbnails.
Perhaps you can tell us more about your use case so we can better help.
You're trying to load multiple large bitmaps, at least one of which is ~12MB. They're too large. The solutions you posted DO work. Resize your bitmaps to something much smaller, especially as you're just displaying the bitmaps on the screen.
Related
I'm using RecyclerView and CardView for my layout and want to display a watermark which spans across 4 cards on the screen. I've chopped up the watermark image into 4 separate images, one for each card (each image already has the dimensions I want it to be displayed with). To display the images, I am using ImageView inside of each card's .xml file as such:
<?xml version="1.0" encoding="utf-8"?>
<android.support.v7.widget.CardView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:card_view="http://schemas.android.com/apk/res-auto"
android:id="#+id/cardview"
android:layout_width="415dp"
android:layout_height="89dp"
android:layout_marginTop="0dp"
android:elevation="100dp"
card_view:cardBackgroundColor="#ffffff">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<ImageView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:src="#drawable/watermark_card1"
android:scaleType="centerCrop" />
.
.
.
</RelativeLayout>
</android.support.v7.widget.CardView>
This works fine while I am only loading 2 out of the 4 images, but when I load the 3rd one, I get the following error:
java.lang.OutOfMemoryError: Failed to allocate a 210446976 byte allocation with 4194304 free bytes and 101MB until OOM
I believe that this is because the images are all very large (521K, 976K, 611K, and 933K) and I am wondering what I could do to use less memory and avoid the OutOfMemory Error. Any advice would be appreciated, thanks!
you must resize or reduce quality of image. and use image library like volly or picasso. this library can solve variety problem relate with image.
In AndroidManifest.xml file, inside the application tag add the below line
android:largeHeap="true"
But, remember this only increase the heap memory and give you solution. But, it's not the best practice. You should recycle your memory properly.
Refer the links
Strange out of memory issue while loading an image to a Bitmap object
Android: convert Immutable Bitmap into Mutable
You can downsample the image as you create it using BitmapFactory. You would just include the images as assets and get an input stream to them, then create downsampled Bitmap objects. This way, you can decide how large you want the images to be based on the device, screen size, memory available, etc. After you create the Bitmap object, use ImageView.setImageBitmap() to set it into your image view. Below is an example of a downsampling method -
public static Bitmap decodeBitmap(InputStream decodeStream, byte[] decodeArray) throws IOException
{
BitmapFactory.Options options = new BitmapFactory.Options();
Bitmap bitmap = null;
boolean useStream = ((decodeStream != null) ? true : false);
int actualFileSize;
// get the decoded object size without actually decoding and creating the object
options.inJustDecodeBounds = true;
if (useStream)
BitmapFactory.decodeStream(decodeStream, null, options);
else
BitmapFactory.decodeByteArray(decodeArray, 0, decodeArray.length, options);
actualFileSize = options.outWidth * options.outHeight * 4;
if (useStream)
decodeStream.reset(); // reset the data - we assume the underlying input stream implements reset() in a
// way that will not throw an exception in the case where the stream is not marked
if (actualFileSize > MAX_BYTES)
{
options = new BitmapFactory.Options(); // recreate the options to get the defaults back
if (actualFileSize/4 <= MAX_BYTES)
options.inSampleSize = 2; // a sample size of 2 has 1/4th the pixels
else if(actualFileSize/16 <= MAX_BYTES)
options.inSampleSize = 4; // a sample size of 4 has 1/16th the pixels
else
options.inSampleSize = 8; // if it is still too big, attempt a sample size of 8 (1/64th the pixels)
if (useStream)
bitmap = BitmapFactory.decodeStream(decodeStream, null, options);
else
bitmap = BitmapFactory.decodeByteArray(decodeArray, 0, decodeArray.length, options);
}
else
{
if (useStream)
bitmap = BitmapFactory.decodeStream(decodeStream);
else
bitmap = BitmapFactory.decodeByteArray(decodeArray, 0, decodeArray.length, null);
}
return bitmap;
}
Finally, as you're loading your images in code, I have found it helpful to force garbage collections (via System.gc()) before and after each call do decodeStream(). When you are done with the Bitmap objects, dispose of their memory explicitly using Bitmap.recycle(). Memory management with large bitmaps on Android can get a little hairy - there are some other suggestions here -
https://developer.android.com/training/displaying-bitmaps/manage-memory.html
Hope this helps.
OutOfMemory error means your images are large in size, so either you decrease quality of the image or use an image library so that it caches your image and also if it still doesnt help then make largeheap=true in your application tag in manifest file.
To avoid this error you have to follow recommendations from this link:
https://developer.android.com/training/displaying-bitmaps/load-bitmap.html
(and look the next two tutorials).
But the easiest way to do it is use one of popular libraries (as were said in one of the answers) - e.g. Picasso (http://square.github.io/picasso/).
In my android app i have set the image on ImageView capture by camera. its working fine. but when i capture image and back to the screen with setting that image on imageview and if i do this 3 to 4 time i got This ERROR BITMAP SIZE EXCEEDS VM BUDGETS ...................please need any solution for it.
this is my code below :
BitmapFactory.Options options = new BitmapFactory.Options();
options.inSampleSize = 4;
options.inTempStorage = new byte[16 * 1024];
image_from_camera.setImageBitmap(BitmapFactory.decodeFile(
"/sdcard/"+chore_string+".jpg", options));
i have done using bitmap.recycle(); or System.gc();
but this is not working . i need to have free the memory from bitmap when again camera button click to take second picture in app. PLEASE NEED ANY HELP........
THANKS. ...
increasing the value of the inSampleSize will decrease the memory overhead required to load the image. Change it to 8,12 or 16... and the image should eventually load but it might not look very good.
However, it seems like you might be using a good bit of memory prior to the load.
Use System.getRuntime() to get the runtime and then see what your max memory, total memory and free memory are to better understand how much space you have.
It's possible you are leaking memory prior to this allocation.
http://developer.android.com/reference/java/lang/Runtime.html
also (annoyingly) if you are using a device that can't run android 3.0 not all of the memory used will show up in the runtime calls. consider using a 3.0 device to more fully understand the memory usage.
This question already has answers here:
Strange OutOfMemory issue while loading an image to a Bitmap object
(44 answers)
Closed yesterday.
I am getting the following error after creating bitmap second time around:
04-17 18:28:09.310: ERROR/AndroidRuntime(3458): java.lang.OutOfMemoryError: bitmap size exceeds VM budget
this._profileBitmap = Bitmap.createBitmap(_profileBitmap, xCoor, yCoor, width, height);
From log:
04-17 18:27:57.500: INFO/CameraCropView(3458): Original Photo Size: W 1536 x H 2048
04-17 18:28:06.170: INFO/CameraCropView(3458): xCoor: 291
04-17 18:28:06.170: INFO/CameraCropView(3458): yCoor: 430
04-17 18:28:06.170: INFO/CameraCropView(3458): Width: 952
04-17 18:28:06.170: INFO/CameraCropView(3458): Height: 952
Since the image is huge I get the error. But the interesting thing is the error does not happen the first time, only when I take the picture the second time, which makes me believe this profileBitmap is NOT destroyed. How do I clean this up?
I had the same problem and fix it this way:
My app was ~18MB size, and when I see how much memory left free I was shocked - 654KB (on 1GB RAM!). So I just deleted almost all images from project and downloaded them from the internet on first start, and use pics from SD card when needed.
To check total/free memory for your app use:
Runtime.getRuntime().totalMemory();
Runtime.getRuntime().freeMemory();
EDIT: I forgot the main thing - add in your manifest, between application tag, this line:
android:largeHeap="true"
There are many problems with memory exceptions with bitmaps on Android, many of which are discussed on stackoverflow. It would probably be best if you went through the existing questions to see if yours matches one of the existing ones, then if not, write up what makes your situation different.
Some examples:
Out of memory exception due to large bitmap size
Android: out of memory exception in Gallery
Android handling out of memory exception on image processing
etc:
https://stackoverflow.com/search?q=android+out+of+memory+exception+bitmap
I have explained it in this blog post: android bitmap processing tips
Now here are tips which you can follow and can avoid out of memory exception in your Android Application.
Always use Activity context instead of Application context. because Application context cannot be garbage collected. And release resources as your activity finishes. (life cycle of object should be
same as of activity).
2 . When Activity finishes. Check HEAP DUMP (memory analysis tool in Android studio).
If there are objects in HEAP DUMP from finished activity there is memory leak. review your
code and identify what is causing memory leak.
Always use inSampleSize
Now what is inSampleSize ?
with the help of inSampleSize you are actually telling the decoder not to grab every pixel in memory, instead sub sample image.
This will cause less number of pixels to be loaded in memory than the original image. you can tell decoder to grab every 4th pixel or every second pixel from original image.
if inSampleSize is 4. decoder will return an Image that is 1/16 the number of pixels in original image.
so how much memory you have saved ? calculate :)
Read Bitmap Dimensions before loading into memory.
How reading bitmap dimensions before loading image into memory can help you avoid out of
memory error ? Let's Learn
use inJustBounds = true
here is technique with the help of which you can get image dimension beore loading it in memory
BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
Bitmap bitmap = BitmapFactory.decodeResource(getResources(), R.id.myimage, options);
int imageHeight = options.outHeight;
int imageWidth = options.outWidth;
String imageType = options.outMimeType;
Above code snippet will not give us any image/bitmap. it will return null for bitmap Object.
but it will definitely return width and height of that image. which is R.id.myimage.
Now you have width and height of Image. you can scale up or scale down image based on these factors:
ImageView size which will be used to display Image.
Available amount of memory. you can check available amount of memory using ActivityManager and getMemoryClass.
Screen size and density of device.
Use appropriate Bitmap Configuration
Bitmap configurations is color space/color depth of an Image. Default bitmap Configuration in Android is RGB_8888 which is 4 bytes per pixel.
If you use RGB_565 color channel which use 2 Bytes per pixel. half the memory allocation for same resolution :)
Use inBitmap property for recycling purpose.
Do not make static Drawable Object as it cannot be garbage collected.
Request large heap in in manifest file.
Use multiple processes if you are doing lot of image processing(memory intensive task) or use NDK (Native Development using c, c++)
You can try calling recycle() on the bitmap when you are done with it. This will clear all the image data and free up the memory. If anything tries to draw the bitmap after this then your app will crash. If you do get a crash it may help you find out what is still holding onto your bitmap.
This happens because you are loading the bitmap directly,which consumes a lot of memory.
Instead use a scaled down version of the picture in _profileBitmap.
This guy explains it pretty well.
http://androidcocktail.blogspot.in/2012/05/solving-bitmap-size-exceeds-vm-budget.html
With Larger images it can be avoided by sampling them into smaller size.
Use below example -
File f = new File(selectedImagePath);
// First decode with inJustDecodeBounds=true to check dimensions
final BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
BitmapFactory.decodeStream(new FileInputStream(f), null, options);
// Calculate inSampleSize
options.inSampleSize = calculateInSampleSize(options, 720, 1280); //My device pixel resolution
// Decode bitmap with inSampleSize set
options.inJustDecodeBounds = false;
Bitmap bmpPic = BitmapFactory.decodeStream(new FileInputStream(f), null, options);
Bitmap bmpPic1 = Bitmap.createBitmap(bmpPic, 0, 0, bmpPic.getWidth(), bmpPic.getHeight(), mat, true);
img.setImageBitmap(bmpPic1); //img is your ImageView
Reference-
http://developer.android.com/training/displaying-bitmaps/load-bitmap.html
You could use a vector Drawable . It uses an xml file to describe your image , so it consumes less memory.
To do that you should use the SVG format for your images and then generate the xml file using one of these 2 solutions :
Solution 1 : Use the vector asset studio in Android Studio : right click on Drawable file in your project -> new -> vector asset
Solution 2 : Use the svg2android website : https://inloop.github.io/svg2android
Check out this link for further information:
https://developer.android.com/studio/write/vector-asset-studio.html
I had the same issue when the phone was powered off and back on. Simply setting the bitmaps to null and calling System.gc(); fixed all the problems.
I had this issue because I was modifying a bitmap once, and then modifying the modified version a second time, resulting in three versions of the same bitmap (original, plus the two modified versions) being in memory at the same time.
I fixed it by changing my image-editing code to apply both modifications to the same bitmap as a kind of batch process, halving the number of modified versions that my app had to hold in memory.
I read many discussions about the inSampleSize OutOfMemory dilemma.
Cannot get a good solution so i ask a question about it.
Im currently loading a bitmap with inSampleSize=4.
That will give me a Bitmap with the size 648x388.
Original On disk size is 2592x1592.
Im writing text on 648x388 bitmap and saving it back to disk.
Im writing on the 648x388 because the 2592x1592 give me OutOfMemory .
The way it works is that there can be 1-10 648x388 Bitmaps to be saved in a while loop.
I want to change this loop to save 1-10 2592x1592 Bitmaps.
How can i securely load the 2592x1592?
I don care about the resolution going down 60% or more.
As long as the Bitmap has the same size 2592x1592.
Is there a way to maybe keep the size but make Bitmap thinner,
removing color without making quality bad.
My first thought was going something like this to get the biggest bitmap i could get:
I have not tested this but get a feeling it's a bad way
boolean work = true;
int insample = 2;
BitmapFactory.Options options = new BitmapFactory.Options();
while(work){
try{
options.inSampleSize = insample;
bitmap = BitmapFactory.decodeFile(filePath,options);
work = false;
}catch(Exception e){
insample++;
}
}
any help would be grate.
Image processing requires a lot of memory. you cant use the whole bitmap and just modify it on your phone. use a web service for that. upload, process, download. sorry there is no other way a decoded bitmap just takes a lot of memory.
And by the way you cant catch an outOFMemory Exception. the app just crashes.
There's a hard limit on process size in Android and a 4 mega-pixel image at four bytes a pixel will hit it all by itself (on many devices), without any room for your program.
I think you are going to need to do one of two things: Create a web service to do the image processing on a server/in the cloud; or learn to do your image processing "on-the-fly" by manipulating the data directly instead of using a bitmap.
I have an Activity which takes photos (with full possible resolution, so quite large), the application have then the chance to analyze them. Only one photo is handled at a time. The problem is that I run in to a "Out of memory" after 4 - 5 photos. I see
dalvikvm-heap Out of memory on a 5070745-byte allocation
(the byte size varies) followed by
Camera-JNI Couldn't allocate byte array for JPEG data
My application does not crash but as it appears to me the Camera simply becomes unable to deliver the images from this point on. I pay attention to memory usage in my application but here it seems that there is a memory leak somewhere outside and I'm asking me how can I cope with this. Any solution approaches existing for this?
This may not be exactly what you are trying to do, but in order to display multiple large pictures (4-6 MB) on a grid view, I found this code to create a smaller bitmap with lower quality, to avoid out-of-memory situations:
BitmapFactory.Options options = new BitmapFactory.Options();
options.inSampleSize = 5;
options.inPurgeable = true;
options.inInputShareable = true;
Bitmap bm = BitmapFactory.decodeFile("/sdcard/myapp/" + filesFound.get(position), options);
The options are the important part, and by varying the settings, I managed to take memory down from where it would crash, to around 28MB when I started using the inSampleSize. It further went down with the inPurgeable and inInputShareable settings set to true. My activity is still sluggish, but it's much better.
For your application, if it can analyze a bitmap, the above code may shrink down the memory usage enough to make it work. I'm still new to Android, so it's possible this may not work at all.. ;-).
Regards,
Kevin
Since you run out of memory after 4-5 pictures you probably arent calling yourBitmap.recycle(); after it has been saved to the SD-card?
Also in the onPictureTaken() method you could save the tempData from the picture into a bitmap using the Bitmap.Config.RGB_565 instead of ARGB(default) if you don't need the alpha channel.
// Create options to help use less memory
Options opt = new Options();
opt.inPreferredConfig = Bitmap.Config.RGB_565;
// Decode the tempdata into a bitmap, with the options as the last argument
bitmapFromRawCameraTempData = BitmapFactory.decodeByteArray(rawCameraTempData, 0, rawCameraTempData.length, opt);