Android bitmaps in xml leak memory? - android

Here are some newbie memory management observations to which I would like
hear an experienced opinion.
It seems that setting android:backgound="#drawable/xyz" in a xml
layout causes memory loss in my app. The respective activities keep
stacking up until I get an OOM error. This is especially true if I rotate
the device orientation.
However, if I load the same resource with setBackgoundResource(), and then clear the
callback and set the background reference to null, there is no leak whatsoever.
that is, first in onCreate()
mMainLayout.setBackgroundResource(R.drawable.background_general_android);
and then in onDestroy()
mMainLayout.getBackground().setCallback(null);
mMainLayout.setBackgroundDrawable(null);
Is this roughly correct, or am I missing something essential?

This would only happen if you keep a copy of the drawables in a static cache for instance. You might also be leaking your activities and setting the drawables to null simply hides the problem for a little longer. You should use a tool like MAT to inspect the content of your heap and figure out what's going on.

Related

Android ImageViews Causing Memory Leak?

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);

Memory management when changing src for ImageView

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!

Android Drawables memory leak

I work with several large drawables and I don't know how to manage memory leaks.
I tracked the heap size of my application and it doesn't stop to grow (as the allocated memory).
It is especially the "byte array (byte[])" type which grows up and never decrease. (in the DDMS Heap view on Eclipse)
My application is composed of one activity which uses fragments.
Those fragments are displaying several large images.
I tried to set drawables callback to null, set drawables to null, clear my volatile cache (which prevent my app from doing too many disk IO) when I pop back a fragment but the heap never decrease.
In fact, each time I call :
Drawable.createFromResourceStream(context.getResources(), value, new FileInputStream(f), f.getName(), opts);
the heap grows up. How can I free memory ?
Thanks !
A memory leak happens when Java finds objects in the memory that are referenced by your code which is preventing the Garbage Collector from freeing this memory. A common cause in Android is referencing the Activity context rather than the Application context. Make sure your context references the Application (i.e. use getApplicationContext rather than using this. Check this video for explanation on Memory leaks and also check this question.
The question seems answered but a post by Romain Guy seems relevant to get more info: Avoiding Memory Leaks.
Apparently, if you (for example) set a drawable as a background image to a text view by using setBackgroundDrawable* (thus attaching the drawable to the view) then change the orientation (destroying the Activity and redrawing the UI) the drawable will still have access to the old activity (after the old activity's destruction), thus creating a memory leak.
*(as a side note - setBackgroundDrawable has been deprecated since API level 16)

Android memory leaks designing layouts

My application is designed with all layouts in res folder as application is image processing; it deals with large sized bitmaps, and is giving out of memmory error. I want to know what is the good approach.
Designing layouts programatically
Using layouts from res folder.
If I am designing all layouts in program I can cleanup all layouts myself in onDestroy() method which I can't if layouts are declared in XML.
I think the best way is to use the XML way because is more faster and reusable.. if you don't pass your current's activity context to another activity, android will take care of cleaning your layouts..
You can clean the inflated layouts in onDestroy() if you want, exactly how you do with the coded layouts. But I don't think it's necessary.
If you are using large bitmaps and changing them after creating them make sure that you call recycle on all bitmaps that are not used anymore. This is the only point where a manual Memory Management in Android is needed.
Recycle will free the native storage that the bitmaps takes up in the current Android Versions. It is unlikely that the memory used by your layout will cause the memory problems. Concentrate on the Bitmaps Objects you are creating.

The Infamous "Exceeds VM Budget" Issue

So I have an APP that loops and continuously draws many png files to a canvas. In the constructor for the thread, for some of the pngs I declare Drawable and some Bitmap handles and assign them (respectively) like so:
Drawablename = context.getResources().getDrawable(R.drawable.pngresource);
mBackgroundImage = BitmapFactory.decodeResource(res, R.drawable.bckgrnd);
Keep in mind I do both methods, MANY times. (even though most of the images are fairly small)
Well... the problem i'm getting is that when trying to start this app on older devices (specifically like the original droid and older) it force closes with the VM budget error.
From research, I've noticed that this seems to be a common problem. (The app runs fine on all newer devices such as droid x, every tablet at best buy, charge, atrix, etc.)
So my question is could I be doing something better?
Is one of these methods of referencing the pngs superior?
Also What exactly is happening here? I need to be able to reference the Image to draw at any time. In other words, at any given instant I could call Draw on one of the handles.
The fixes I've seen for similar problems involve calling the Garbage collector, but would that help me since I would need the Images later anyway? Or is this exclusively a problem with the way i'm referencing the pngs from the drawable folder?
Sorry if this is confusing, i'm a beginner.
If I called System.gc() after every reference would that help, even though the reference is still stored as a Drawable object?
The common fix:
Resize image size, for example: createScaledBitmap()...
Reduce image quality, Config.inSampleSize setting...
Remove all references to Bitmap objects when un-used (setting references to NULL, of course). If you don't do this, System.gc() will does nothing, remember this! and this method call does not guarantee that the memory will be freed right away.

Categories

Resources