I need to set a different background to layout based on some event. This was causing OOM exception. I added code to fix this but this is now causing recycled bitmap issue.
Here is the code:
if (change_bg != 0) {
//Garbage collect the current BG.
BitmapDrawable bg = ((BitmapDrawable)llayout.getBackground());
llayout.setBackgroundResource(0);
if (bg != null) {
bg.getBitmap().recycle();
bg = null;
}
System.gc();
llayout.setBackgroundResource(change_bg);
llayout.invalidate();
}
This does not happen the first time but after some 4-5 events randomly.
If I do not call bg.getBitmap().recycle, the OOM exception is encountered.
Can anyone point out the mistake or suggest the correct method to set the layout background
in the same view?
Note:
I removed the android:background="#drawable/bg_initial" in the ;ayout but it had no effect.
The App is using other views with layouts having background image and the problem
is not seen with those views.
Prima facie this does not seem to be memory issue but problem when setting a different
background in the same view. I can implement a different to switch the background image
but this seems overkill. Would be glad if someone offers a simple and real solution.
EDIT :
I added the background bitmap garbage collect code in OnDestroy() and that seems to have
solved the issue.. atleast I am not able to recreate the problem now.
But I am wondering what is the explanation for this. I am not holding the layout or
images in a static variable so I am not sure it was held in memory. I am wondering
what is going on. Can someone explain this?
This might be because the imageView is referring to the image, and before you setting a new background image, you are recycling the previous image (which is still referred by the imageView), and hence its throwing the exception.
Try following:
Get the previous background by BitmapDrawable bg = ((BitmapDrawable)llayout.getBackground());
Now set new background
Garbage collect the previous background.
Please see my answer to solve OOME, it might help you. bitmap size exceeds Vm budget error android
Related
suppose that I have just one ImageView inside a HorizontalScrollView. The problem I'm facing is I have to create a very wide Bitmap to place it inside my ImageView and, obviously, use the scroll from HSV to see all my image there. I'm getting a lot of OutOfMemoryException so, is there any technique to get this task done without getting a ton of OutOfMemoryExceptions?
You are getting OutOfMemoeryException because your bitmap is too large to load the entire bitmap into memory (a loading issue not a rendering issue).
Instead you need a custom image view that downsamples and/or only loads sections of the image at a time depending upon what part of the image should be currently visible.
This may not fit your use case but it is an example of this problem being solved by downsampling
I'm the sole developer on an app for the company I work for. I'm new at app development and I've nearly finished the app but when I was testing, I noticed the heap size grows while navigating the app up to 3x the starting amount until GC runs and knocks it back down. I ran MAT and saw that it had to be something with bitmaps. I am currently changing the icons to an "on" state every time they are touched. This means I just changed the icons to a different colored image to give the visual appearance of being "tapped" such as below.
ImageView callButton = (ImageView) findViewById(R.id.callButton);
callButton.setImageResource(R.drawable.call_on);
They are then turned "off" from onResume such as below.
ImageView callButton = (ImageView) findViewById(R.id.callButton);
callButton.setImageResource(R.drawable.call_off);
I do this for every icon throughout the app. My question is whether this is causing the memory leak from creating so many ImageViews. Should I set them to null onDestory?
No, you do not need to set bitmaps to null in onDestroy. Especially not if you're using images from resources, which references are kept to in Resources anyway. What you may want to consider is using a StateDrawable and changing the state rather than switching drawable's all the time, just for your own sanity. But this kind of usage shouldn't be causing OOMs unless you have a lot of images or other issues.
Release your bitmaps as soon as possible using setImageDrawable(null) like -
callButton.setImageDrawable(null);
I am still new to Android, and never had to deal with memory management in my previous experience.
In my android application, I have an activity with a TextView, a ListView, and ImageView. I have listeners for the textview and listview, and the code that changes the contents in all three of those views. The contents is stored in the arraylist. The source for the ImageView is stored in form of a String (filenames), and the code that makes the changes looks like this:
tv1.setText(myText);
imgView.setImageResource(myImage);
This worked perfectly well while I only had a few images to test the logic, but once I added more images, I started to get the OutOfMemory error. If I make the images smaller, I get that error a little later in the process, but I still get it.
At first, I thought that Android does not release the previous source, so I thought using recycle() before the reassignment will help. Instead, I've got another error when I try to change the source:
Cannot draw recycled bitmaps
It looks like I am missing some vital understanding about how the ImageView handles the source images. Does it assign the bitmap reference and then keeps the same reference, but somehow changes content?
Then, after reading this article, I realized I have a different kind of problem altogether, the one that might be solved by using the inBitmap. Yet, the documentation says the bitmaps have to be the same size for that, and mine are not.
I am thinking of converting my drawable to bitmap, then scaling it to some hard-coded dimensions, then using inBitmap. I guess my second question is - does this approach make sense? Are there any downfalls in scaling the images? And any examples would be appreciated, of course.
Thank you!
In my app I have 3 activities as tabs. All of them have 4 ImageView. I set background of these views by using setBackgroundDrawable method. I cant use layouts, because my bitmaps are dynamic, coming from internet. I checked size of bitmaps, they are normal, already i get error (Out Of Memory) after i click different tabs 3. time, no matter order.
I get the error just in hd phones, probably it is about scaling bitmaps to up.
I have found the solution.
the reason of the error is that I created the bitmaps in onCreate method and set them to background of views.
As a solution I create the bitmaps in onResume method, set backgrounddrawables and in onPause method I set bakground drawables to null.
In my activity I have
final ImageView img = (ImageView) findViewById(R.id.myimage);
img.setImageDrawable(getdrawable()); //getdrawable() is my own function which returns a drawable
Then this line
img.setImageDrawable(getdrawable()); //this line is
is called many times to replace the drawable on the current imageview.
Will I need to recycle the drawable or will the GC do it for me? and if i do need to recycle then how do i do it?
Drawables, like anything else that uses memory, get marked for garbage collection whenever there are no longer any references pointing to them. If you're running into a situation where memory isn't released as soon as you drop the reference to the previous drawable, well, that's GarbageCollector for you. GC will try to do its work in the most efficient way possible, which means that, from your perspective, it gets to it when it gets to it, and you can't make it go any faster, even if you call the object's dispose() method.
Read this guide for a really good explanation of what's going on under the covers with garbage collection.