createBitmap() leads me into a java.lang.OutOfMemoryError - android

i try to rotate 3 imageViews (or better the Bitmaps behind them) every 10-100ms.
i do the rotation like this:
ImageView ivLoad;
Bitmap bMapLoad;
....
Matrix mat=new Matrix();
mat.reset();
mat.postScale(1.55f, 1.55f);
mat.postRotate((float)currentLoadDegree+(float)LoadDegree);
bMapLoad = Bitmap.createBitmap(bMapLoadgr, 0, 0, bMapLoadgr.getWidth(), bMapLoadgr.getHeight(), mat, true);
ivLoad.setImageBitmap(bMapLoad);
ivLoad.setScaleType(ScaleType.CENTER);
....
the first time i start the app everthing works fine.
second time also works
but the 3rd time i start the app it crashs with the following error:
03-27 10:01:09.234: E/AndroidRuntime(3603): java.lang.OutOfMemoryError
03-27 10:01:09.234: E/AndroidRuntime(3603): at android.graphics.Bitmap.nativeCreate(Native Method)
03-27 10:01:09.234: E/AndroidRuntime(3603): at android.graphics.Bitmap.createBitmap(Bitmap.java:605)
03-27 10:01:09.234: E/AndroidRuntime(3603): at android.graphics.Bitmap.createBitmap(Bitmap.java:551)
after trying around a long time i found out that when i call System.exit(0) in the onDestroy methode everthing works.
now i don't know if there would be a better way because on google a lot of peaople mean that System.exit(0) is unsafe.
so will i get problems with this?

Instead of rotating the Bitmap, you could rotate the canvas you are drawing on.
canvas.save();
canvas.translate(-canvasWidth/2, -canvasHeight/2);
canvas.rotate(degrees)
canvas.drawBitmap( ... )
canvas.translate(-canvasWidth/2, -canvasHeight/2);
canvas.restore();
Now you only get a new bitmap, when the image itself is updated, even though you can rotate it as frequent as you like. But if you get a new Bitmap, you still need to call Bitmap.recycle() on the old one.

You shouldn't recreate the bitmap on every step of the rotation, instead you should just try to draw it rotated. That's also possible with a Matrix (what you already use) and will avoid the excessive memory usage.
Android: How to rotate a bitmap on a center point

You get OutOfMemoryError because you load the Bitmap every time you rotate ImageView. You should consider reusing already loaded bitmap. Also call Bitmap.recycle() method when you do not need the bitmap any more.

Related

Out Of Memory Error in Android Studio

I'm trying to create my first android app, so I'm really new to android development. I'm trying to make a nice background image for my app. I made an image that is the exact dimensions of the device, but when I try to load it, i get the error "Failed to allocate a 218748 byte allocation with 217220 free bytes and 212KB until OOM" Here's my code:
#Override
protected void onDraw(Canvas canvas) {
drawBackground(canvas);
protected void drawBackground(Canvas canvas) {
Bitmap background = Bitmap.createBitmap(BitmapFactory.decodeResource(getResources(), R.drawable.background2));
canvas.drawBitmap(background, 0, 0, null);
I've tried scaling it down, which works, but then it doesn't fill the entire screen. How do I resolve this issue?
You should recycle bitmap after canvas.drawBitmap(background, 0, 0, null);, or create bitmap once, in the constructor, and then use it, it is very costly to create bitmap each time in the onDraw method, it even costly to create simple objects in the onDraw, you shuold avoid from it, android:largeHeap="true" and System.gc() can't help in this case. Read this
Custom Drawing
Creating objects ahead of time is an important optimization. Views are redrawn very frequently, and many drawing objects require expensive initialization. Creating drawing objects within your onDraw() method significantly reduces performance and can make your UI appear sluggish.
There is blog that will help you to detect and prevent Out of memory issue. I wrote this based on a real problem I faced and here is the link
If you got stuck anywhere in the tutorial please let me know we can discuss and if you want to add something please suggest.

Android: Rotating large image crashes without throwing an error

I have searched and found simple code to rotate an image. I am pulling the image out of an ImageView object into a bitmap, rotating it then putting it back. I realize this is not the most effective method but I don't think it should crash without giving an error message in the CATCH block.
Here is my code. The only value passed in is "r" or "l" depending on which direction I want to rotate. Smaler images (1500x1500 or smaller) work just fine. Things go bad around the 2500x2500 size.
public void rotate(String dir)
{
try
{
float angle = (dir.equals("r") ? 90 : -90);
Bitmap bitmap = ((BitmapDrawable) imageView.getDrawable()).getBitmap();
Matrix matrix = new Matrix();
matrix.reset();
matrix.postRotate(angle);
bitmap = Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), matrix, false);
imageView.setImageBitmap(bitmap);
}
catch(Exception e)
{
Utilities.logError(e.toString());
}
}
Any clue as to why it is crashing and why it doesn't thow an exception? I just get a message "Unfortuantly process .... has stopped" and I get kicked back to the welcome screen of my app.
Oh, for kicks I set the angle to ZERO (hard coded) and it didn't crash. I suspect that it is just taking too long to rotate and Android is having a fit. But I am not sure how to confirm that as the problem or how to tell Android to wait a little longer.
Even if I reduce the preview image for the rotation, when I go to save I will have to rotate the full size image at least once and will hit this same issue. Won't I?
I can more or less guarantee without looking at the logs that you're getting an Out Of Memory Exception.
You need to use smaller images, or use a different method to rotate that doesn't use up so much memory (you're allocating 2 2500x2500 bitmaps at the same time here! that's tons!).
Try using a RotateAnimation to get your effect instead.
Hope this helps :)

Avoiding java.lang.OutOfMemoryError

Hi all I am developing live wallpapers, and I am using lot of bitmaps. I have tested my new live wallpaper for aboute a week, and it was up and runing perfectly, but as soon as I have uploaded it to a market I keep getting this kind of exceptions : java.lang.OutOfMemoryError for both android.graphics.Bitmap.nativeCreate and android.graphics.BitmapFactory.nativeDecodeAsset. I use this kind of lifecycle of an bitmap:
I create a reference like:
Bitmap dark = null;
Bitmap cave = null;
at onCreateEngine I init them like :
cave = BitmapFactory.decodeResource(getResources(), R.drawable.cave);
dark = BitmapFactory.decodeResource(getResources(), R.drawable.dark);
here is where it trows the exception. for these images: . and after all I draw them to an canvas like this:
canvas.save();
canvas.drawBitmap(bg, new Matrix(), new Paint());
canvas.drawBitmap(dark, new Matrix(), new Paint());
canvas.restore();
What Should I do? It is better to load the dark image just one picture and draw it to the canvas width*height times? Or Are there any methods to do? I think recycle or calling onDestroy. But I do not know when to call them because the exceptions are thrown at onCreate.Are the images too big? And why it is working smoothly on my device, and on the other devices it is throwing exceptions? The bitmaps are 1484*1484 dimension big and the clouds are 250*172 dimensional big, should they be in 2^x * 2^x dimension?
Just try to use Memory Optimizer and see where are you creating Memory Leaks. You can use Eclipse Memory Analyzer(MAT) for this. Its a very common problem with using bitmaps. By using BitMaps you need to be extra careful for memory leaks.

How to Clear Bitmap Memory in Android?

I created a Bitmap and use it in Canvas to draw a circle and this method is called every time the Activity gets called and Activity get called multi-times so that time I am getting some error like 1536000-byte external allocation too large for this process
I know that error is Memory issue but how to Clear bitmap and also use at second time Activity call..
My Code is :
private void Draw_Hold_Circle() {
Bitmap bitmap_hold = Bitmap.createBitmap(width, height,
Bitmap.Config.ARGB_8888);
Canvas canvas_hold = new Canvas(bitmap_hold);
canvas_hold.drawArc(rect_open, 0, 360, false, mOutlinePaint);
}
This Method is called 4 times and the MainActivity can call multi-time so How to maintain Bitmap and its Memory?
Is there any special reason why you want to mantain the image in memory? If I'm not wrong you call your method "everytime your activity is called" so I'm guessing you mean everytime it's started with startActivity(). If this is the case then there is no point on maintaning all the images in memory at once since the user will be able to see the one on your foreground activity. I would suggest you to save your image to a file on your onStop() method and rebuild it, if necessary, on your onResume() method.

Bitmap size exceeds VM budget, not understanding why

I've looked all over for "Bitmap size exceeds VM budget" problems, but none of the solutions seem applicable for me. I am not understanding why my program sometimes throws this error because they way I'm using it doesn't seem to cause any possible memory leaks. My stack traces are pointing to the BitmapFactory.decodeResource() method. I've got a background image that I'm using to draw on a Canvas and this is how I've been initializing it:
Bitmap backgroundImage = BitmapFactory.decodeResource(getResources(),
R.drawable.background);
backgroundImage = resizeImage(backgroundImage, w, h);
This is how I've been using it:
canvas.drawBitmap(backgroundImage, 0, 0, paint);
I thought that putting backgroundImage = null in the onDestroy method would help, but that did nothing. There is not other reference to the background image resource in my program except in an XML file, but I don't think that affects it. Could someone explain to me why this is happening and how to fix it?
By the way, there is not screen orientation changes involved in this app.
You need to free the bitmap pixels when you're done with it. You mentioned that you set its value to null, but that only makes it eligible for GC, it does not explicitly tell the VM that you're done with those pixels, and that now is a good time to free them.
Before you set it to null, simply call Bitmap#recycle() on the Bitmap:
protected void onDestroy() {
if (this.backgroundImage != null) {
this.backgroundImage.recycle();
this.backgroundImage = null;
}
}
Additionally, you may be wasting resources in your resizeImage() method, which you did not provide code for. It's much more efficient to do proper down-sampling of the Bitmap at decode-time, rather than loading the full-size Bitmap, and then scaling it down from there.
The general technique is to use the 3-argument version of BitmapFactory.decodeResource(), with BitmapFactory.Options#inJustDecodeBounds for a first-time-pass in order to get the width/height of the Bitmap (although in your case, since it comes from the app's resources, there's no reason you should even have to do that.. but I'll explain it anyway); then determine a proper samplesize based on the target size, and decode the bitmap a second time. That usually results in much less memory usage, especially for very large images (e.g., with inSampleSize set to 2, it decodes the full-size Bitmap, but only allocates enough memory for a Bitmap of half the original size, downscaling the Bitmap in the process).

Categories

Resources