i am creating a bitmap of layout. Its working fine in most of the devices but in few samsung devices, its throwing OOM. Below is the code I am using to convert the layout to bitmap
private void enableViewCache() {
viewToConvert.setDrawingCacheEnabled(true);
viewToConvert.measure(MeasureSpec.makeMeasureSpec(0, MeasureSpec.AT_MOST),
MeasureSpec.makeMeasureSpec(0, MeasureSpec.AT_MOST));
viewToConvert.buildDrawingCache(true);
}
public Bitmap getBitmapFromView() {
Bitmap b = Bitmap.createBitmap(viewToConvert.getDrawingCache());
viewToConvert.setDrawingCacheEnabled(false);
viewToConvert.destroyDrawingCache();
ByteArrayOutputStream bytes = new ByteArrayOutputStream();
b.compress(Bitmap.CompressFormat.JPEG, 100, bytes);
return b;
}
I am getting OOM at Bitmap.createBitmap call. I have checked most of the OOM bitmap issues in stackoverflow which mentioned about using sampling and all but I dont know how to implement that in this usecase.
I'm not sure what you're trying to accomplish, but in MOST cases you don't want to extract a Bitmap from a View. What you usually want is to maintain the bitmap on a different place (LRU Cache maybe?). My guess would be the view's drawing cache is the issue.
Anyway, the problem is probably the way you're handling a large bitmap. Read this article so you know how to sample, scale down, and other techniques so you don't get OOM.
Related
I have a web view that I need to take a screenshot from a site. People suggested me use the function capturePicture(), this function is deprecated. So I create bitmap from current site like this and save it as byte[ ] to the database:
Bitmap bitmap = Bitmap.createBitmap(view.getWidth(), view.getWidth(), Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(bitmap);
view.draw(canvas);
ByteArrayOutputStream stream = new ByteArrayOutputStream();
bitmap.compress(Bitmap.CompressFormat.JPEG, 10, stream);
DatabaseHelper.updateData(id, stream.toByteArray());
bitmap.recycle();
And load it in another Activity with Glide:
Glide.with(context).load(items.get(position).getImage())
.placeholder(R.drawable.ic_defualt)
.into(holder.ivShot);
Now, If the number of screenshots increases, The speed of the app decreases and Memory size increases. I know that the issue of bitmaps is very complicated, But there must be a way to take a picture of the web view without any memory leaks or slowdowns.
I try to use threads to get bitmap but it doesn't help. Anyone know How I can do it?
I am trying to solve problem when I get bitmap from view (with bad quality of childviews) and store it as PNG. There are some taken pictures using this code:
Bitmap b = Bitmap.createBitmap(
Math.round(General.getDisplayWidthPx()), Math.round(General.getDisplayHeightPx()), Bitmap.Config.ARGB_8888);
final Canvas canvas = new Canvas( b );
wallFrame.invalidate();
wallFrame.draw( canvas );
FileOutputStream out = new FileOutputStream(file);
b.compress(Bitmap.CompressFormat.PNG, 100, out);
out.flush();
out.close();
When the childview is small the quality of childview is terrible.
But when it's larger the quality is better.
As you can see the smaller the picture, the lower the quality. I also tried deprecated methods:
wallFrame.setDrawingCacheEnabled(true);
Bitmap b = wallFrame.getDrawingCache();
wallFrame is ZoomLayout which extends RelativeLayout. Child views in wallFrame are SubScalingImageView which extends View. I think it's not caused by SubScalingImageView I've tried standard ImageView and result was the same. When I take screenshot of app, the result is better.
Pictures are loaded from user storage using Uri (so not from drawable). SubscalingImageView has own decoders. In app the quality of pictures is perfect.
I think problem is somewhere in view.draw(canvas). But I have no idea how to edit it to make it work.
I appreciate every idea. Thank you!
I require displaying many images in my application. These being jpgs and pngs and i'm loading them inside ImageViews like so:
tile.setImageResource(R.drawable.tile_highlight);
I am currently having OutOfMemory problems (java.lang.OutOfMemoryError: bitmap size exceeds VM budget)
I've searched and found some other posts, they all suggest that you should recycle the bitmap of an ImageView manually, like so: ((BitmapDrawable)imageView.getDrawable()).getBitmap().recycle(); which will dump it from memory.
BUT in my case, being that i'm not using setBitmap() to load the images onto the ImageView objects, when i try and run the above code, it returns NullPointerException, more precisely, the method getBitmap() returns null, there is no bitmap ?!?!
Do i need to go back in my code and change the way i load all the images in the ImageViews, and then try with the recycle() method? Or how can i free up the memory so it doesn't crash anymore?
EDIT
I've tried something like so: imageView.setImageResource(-1); in hopes it will remove the image from memory and replace it with ... null or something, but it seems it doesn't help the cause.
It would be helpful if you could post some of your code. Specifically, how you're setting the images of the ImageView objects. If you're not using bitmaps, I would expect that getBitmap() will return null. However, if you're using another sort of Drawable or otherwise to set the image, there's likely a similar route to take that doesn't involve bitmaps.
EDIT:
Alright, give this a shot. You can create a Bitmap from a resource like this:
Bitmap bm = BitmapFactory.decodeResource(getResources(), R.drawable.image);
Then, use the bitmap like this, considering img is your ImageView:
img.setImageBitmap(bm);
//Do some stuff with it, then when memory gets low:
((BitmapDrawable)img.getDrawable()).getBitmap().recycle();
Of course, this is considering that you're in an activity. If not, you'll have to get a handle on the context and replace getResources() with context.getResources().
If you want to set an image from drawable to ImageView, Do not use ImageView.setImageResource(int resId) directly with drawable id. Instead get Scaled down bitmap(if applicable) and set it to imageView. like this:
this works for me.
iv.setImageBitmap(decodeResource(getResources(), R.drawable.big_image));
private static Bitmap decodeResource(Resources res, int id) {
Bitmap bitmap = null;
BitmapFactory.Options options = new BitmapFactory.Options();
for (options.inSampleSize = 1; options.inSampleSize <= 32; options.inSampleSize++) {
try {
bitmap = BitmapFactory.decodeResource(res, id, options);
Log.d(TAG_LOG, "Decoded successfully for sampleSize " + options.inSampleSize);
break;
} catch (OutOfMemoryError outOfMemoryError) {
// If an OutOfMemoryError occurred, we continue with for loop and next inSampleSize value
Log.e(TAG_LOG, "outOfMemoryError while reading file for sampleSize " + options.inSampleSize
+ " retrying with higher value");
}
}
return bitmap;
}
source: https://codingjunkiesforum.wordpress.com/2014/06/12/outofmemory-due-to-large-bitmap-handling-in-android/
try
((BitmapDrawable)im.getBackground()).getBitmap().recycle();
I think you should display images with lower resolution. This would resolve the OOM problem. You can also read Android Developer Guideline link
OutOfMemory error comes when you dont free bitmap once its being used(may be large size) so to prevent this we should keep in mind of re-sizing,taking weakreferences etc.
but there are good libraries available which is taking care all problem one of them is Picasso. please have a look at-
loading images using Picasso
I'm developing an Android game consisting of many images as sprites.
When I load the images the following way:
public static Bitmap loadBitmap(int resId) {
return BitmapFactory.decodeResource(getResources(), resId, options);
}
everything works perfectly fine.
When I try to down-scale or up-scale the bitmap with this code:
public static Bitmap loadBitmap(int resId) {
Bitmap bitmap = BitmapFactory.decodeResource(getResources(), resId, options);
Matrix matrix = new Matrix();
matrix.postScale(0.8f, 0.8f);
Bitmap scaledBitmap = Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), matrix, true);
bitmap.recycle();
bitmap = null;
return scaledBitmap;
}
the application crashes with the following exception:
2211840-byte external allocation too large for this process.
Out of memory: Heap Size=4935KB, Allocated=2549KB, Bitmap Size=18463KB
VM won't let us allocate 2211840 bytes
Why is the scaling causing OutOfMemory exception? I even try to recycle the original image in order to save some space. I'm not using Bitmap.createScaledBitmap(...) intentionally, since this method does memory leaking internally (as explained in other online resources).
Thank you in advance,
Zlatko
You are probably just very close to the memory limit. It looks like you are creating a pretty large bitmap (and I'm not sure why you are making it the same size as the original bitmap). From the log, you have used 25MB of Java allocations, and 18MB of bitmap allocations, so you are basically right up against the 48MB heap limit.
Also I think it is very unlikely that createScaledBitmap() leaks. All it does is basically what you are doing here.
You should try to use the variable "inSampleSized" in the BitmapFactory.Options class. This will scale without using excess memory.
http://developer.android.com/reference/android/graphics/BitmapFactory.Options.html#inSampleSize
I guess you´re really close to the heap limit. In your function, you basically are instantiating a second Bitmap, which roughly leads to doubling your memory (Bitmaps are very large). If you´re on an OS earlier than Honeycomb, it´s also misleading to look at memory values, which are printed out somewhere. iirc, Bitmaps are held directly on the system memory heap, whereas everything other is held on the vm heap (and these are the values you see -> 2,5MB). However, the memory for Bitmap allocations also counts in for the memory heap limit. :/
I suggest you have a look at this Google I/O Session: http://www.youtube.com/watch?v=_CruQY55HOk
I think your problem can only be solved by bringing down the resolution of your Bitmap or by using some scale function, that doesn´t instantiate a new Bitmap and modifies the existing one (like the one mentioned by AmandeepGrewal).
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