MemoryLeak through onConfigurationChanged() - android

I have an AsyncTask which I need to "restart" if the user does configurations such as Switch Color.
When he do so I start the AsyncTask like this:
myWorkerClass.clearMemory();
myWorkerClass = new WorkerClass(getApplicationContext(), gv, searchbar, width, scaleButtonText);
myWorkerClass.execute();
In the AsyncTask I add a onTextChangeListener to my EditText!(Which causes the MemoryLeak later).
To prevent MemoryLeaks I have a Method in my AsyncTask which removes the onTextChangedListener:
public void clearMemory() {
searchbar.removeTextChangedListener(myTextWatcher);
}
Everything works fine except when I rotate my device. When I rotate my Device I do only this in onConfigurationChanged:
myWorkerClass.clearMemory();
myWorkerClass = new WorkerClass(getApplicationContext(), gv, searchbar, width, scaleButtonText);
myWorkerClass.execute();
As you can see I do exactly the same thing as if the user changes a Color. But at rotating device I'm leaking Memory, at switching Color I'm not!
This is after switching the Color:
This is after rotating the Screen a few times (remember I do exactly the same as at switching color:
These are my Leak Suspects from the Heap Dump:
This is my dominator tree:
Why do I know the onTextChangeListener is the Problem?
Because if I comment adding a onTextChangedListener to my EditText out, everything works fine. No Memory Leaks.
My Question:
Why does a Rotation Change leak Memory and a Color Change does not when I start the asynctask the exact same way and do exact the same things within the asynctask?
I searched a little bit: http://developer.android.com/guide/topics/resources/runtime-changes.html
But I can't figure out if that is my Problem. The Rotation must do something different, like creating a new activity because of that creating a new reference to my edittext. And because of that he can't remove the old onTextChangeListener.
Please understand. I don't want to make my whole code public. But I think this isn't necessary anyway in this case.

The Rotation must do something different, like creating a new activity because of that creating a new reference to my edittext.
exactly, it destroys your current activity and creates a new one. If searchbar is a member variable of your AsyncTask then consider putting it into WeakReference:
WeakReference<SearchBar> searchbarPtr;
then access using searchBarPtr.get(), but check if its null, if so then it means it was garbage collected due to config change.
Also remember to not make your AsyncTask an inner class of you activity. If it is nested then make it static. Otherwise your asynctask will keep reference to your activity and it will prevent it from being destroyed - until its thread ends.
Unfortuanately making it all work corectly in all situations can be quite difficult and time consuming.
Hopefully no one will suggest preventing destruction of your activity through android:configChanges, implementing correct behaviour of your activity during rotation will prevent it from crashing/leaking in less common activity lifecycle moments which cannot be prevented by android:configChanges.

In android, the rotation destroys your current activity to start a new one.
To avoid it, you can add android:configChanges="orientation|screenSize" in your manifest file.
Below are tips to avoid memory leaks on Rotation change
Do not keep long-lived references to a context-activity (a reference to an activity should have the same life cycle as the activity itself)
Try using the context-application instead of a context-activity
Avoid non-static inner classes in an activity if you don't control their life cycle, use a static inner class and make a weak reference to the activity inside. The solution to this issue is to use a static inner class with a WeakReference to the outer class, as done in ViewRoot and its W inner class for instance
A garbage collector is not an insurance against memory leaks
Source: Avoiding memory leaks

Related

Android - Do I have to have WeakReference for inner class AsyncTask?

LEt's say I have an inner class AsyncTask in an Activity class.
Do I have to have weakRefeernce in this AsyncTask?
Also, do I have to have weakReference for AsyncTask all the time?
Lastly, if I declare inner class AsyncTask as static, is it safe?
Yes always declare your Asynctask static if it's an inner class or just create it's own class, try avoiding declaring as non-static inner class, as it creates memory leaks. Read here for a more elaborate explanation why you should not do this
You do not want to use WeakReference for an Asynctask since the garbage collector of android 2.3+ is very aggressive and will collect all weak refrences very fast. Also weak reference generally is NOT a good pattern for threads, its more for memory footprint heavy obects like bitmaps (but not anymore in android as said before).
From http://developer.android.com/training/displaying-bitmaps/cache-bitmap.html
Starting from Android 2.3 (API Level 9) the garbage collector is more aggressive with collecting soft/weak references which makes them fairly ineffective.
The WeakReference allows the Activity to be garbage collected, so you don't have a memory leak.
A null reference means that the AsyncTask cannot blindly try to update a user-interface that is no longer attached, which would throw exceptions (e.g. view not attached to window manager). Of course you have to check for null to avoid NPE. Hence it is a good practice to use WeakReference to handle the above mentioned situation.
And yes, it is perfectly safe to declare your inner class as static
WeakReference<Activity> weakActivity;
Somewhere in AsyncTask, probably either constructor or onPreExecute:
weakActivity = new WeakReference<Activity>(activity);
In onPostExecute:
Activity activity = weakActivity.get();
if (activity != null) {
// do your stuff with activity here
}
from the activity in which you are starting the AsyncTask,pass this to the constructor. (I assume you write the assignment statement shown above in your constructor.
If you're using the WeakReference for the right reason, then having an aggressive garbage collector shouldn't bother you.
WeakReference means that you're not interested in keeping that object in memory if no one else is strongly pointing to it.
For example, having an AsyncTask that is passed an ImageView to load an image into.
After the AsyncTask is done with it's work if no one is pointing to the image view with a strong reference, that means that the ImageView is no longer visible to the user and it's view has been destroyed, so why would you possibly want to have a reference to a view that has been taken off screen.
So YES i believe that all of your references in an AsyncTask should be weak specially ones that is related to the UI "Views, Activity" stuff like that.
And YES you should have your inner classes declared as static as much as possible, so they don't have an implicit reference to its containing class, which will destroy what we have tried to do by using WeakReference

Is it acceptable to maintain an instance of Context in a class not derived from Activity?

I am developing an application where I've passed the Activity's context into a class derived from Object.
Is there anything wrong with doing this?
Maintaining an instance of a Context like that of an Activity or Service is going to open up ways for memory leaks.
However, keeping a reference to the instance returned by getApplicationContext() should be harmless.
There's nothing inherently wrong at all. Every View class does that, for instance.
The only danger is maintaining a reference to an Activity after it is destroyed. This is a common source of memory leaks. See the blog post Avoiding memory leaks for more information about this.
View subclasses avoid leaking because references to the views themselves generally go away when the activity is destroyed. If your class instance that is maintaining a reference does not go away like that, then you need to arrange for the reference to go away. One option is to override onDestroy for your activity and do some clean-up there. Another is to use a SoftReference instead of a hard reference to the context.

Android class design - should I reinstantiate dialog classes in my activity each time I want to show them?

MainActivity:
GeneralDialogFragment history_dialog = new GeneralDialogFragment();
public void showHistory(View view) {
Bundle bdl = new Bundle(1);
bdl.putString("dialog_type", "history");
history_dialog.setArguments(bdl);
history_dialog.show(getSupportFragmentManager(), null);
}
This code lives inside my activity.
Now, I was wandering whether I should put the definition
GeneralDialogFragment history_dialog = new GeneralDialogFragment();
inside or outside the showHistory() function?
What's the difference? Am I conserving memory if I put it outside (so It's instantiated only once?)
Whether or not you do that is primarily dependent on what the Fragment does. The overhead to create a new Fragment object is miniscule, but can add up depending on how many you need to make. If a DialogFragment is static and pops up every second (why would you do that?!?!), then it would probably be worth keeping it around. If a DialogFragment pops up every minute, then the end user probably won't notice if you're recreating the object every time.
Generally speaking though, Android (Google) recommends doing the lazy-loading approach. So if you created the object at the beginning of that method and called show(), you would lose the reference to it. There will still be a reference to it in the application's FragmentManager, so it will stay in memory. Once you call dismiss(), the Fragment will be removed and its memory that it is taking up will be garbage collected. Doing it this way has a slight CPU overhead, but at the gain of minimizing memory usage.
The exception to this would be if there's a lot of resources that need to be allocated for the fragment. In that case, it would be wise to load the resources once then keep them around. Images for example are better cached because they can take a long time to decode. They don't have to be saved in the Fragment itself, but it would be good for large images to stay in memory and passed to new Fragments as they are being created.
EDIT:
Just a side note, if you do decide that the reference needs to be kept, it would be good to have a check to make sure the dialog isn't already shown. The app will currently crash if you call showHistory() again if the dialog is currently up because you're calling setArguments() on a Fragment that is attached to the Activity.
It depends how many times you want to call the showHistoryMethod() and also do you need the object history_dialog outside the showHistory() method.
So assuming the object is not needed outside the showHistory() method and it will be only called once during the Activity, or not called at all, then place it inside the showHistory() method.
If you place it outside then the instance of GeneralDialogFragment will live during the lifetime of your main Acitivity. Whereas if it is inside the showHistory method than the GarabageCollector will free the memory, once it is not needed.

Android memory leak - deadly embrace

Initially I didn't pay a lot of attention to the possibility of memory leaks in Android, given the nature of managed code / garbage collection and so on. I'm thinking this might have been a bit naive. Here's the question:
Say there is an activity - MyActivity. When the OS starts it, in its onCreate() this instantiates another class (MyOtherClass) and keeps a reference to it. However say the instance of MyOtherClass also keeps a reference to the context - which happens also to be a reference to the instance of MyActivity.
Now something happens - say the screen gets rotated. OS calls the activity onDestroy() and drops the reference to that old instance of MyActivity. However, that activity instance still has a reference to an instance of MyOtherClass, which in turn has an instance to the activity.
So, am I right in thinking those two classes are going to keep each other alive for evermore?
If so, I guess possible answers are (a) don't keep a context reference, get it another way, or (b) in the activity onDestroy() drop any references it has to anything else, then it all ought to just collapse.
Java wouldn't allow cyclic links to keep each other alive (in memory). However if you have declared references static or created singleton style objects, Java won't help you there.
A good start might be reading avoiding memory leaks.

setRetainInstance fragment with UI Android

Ok, I created a Fragment with some UI (couple textboxes and stuff) and I used setRetainInstance since Im running an AsyncTask to query a server (request can only be sent once) and I need the result of the AsyncTask. So my question is:
Is it wrong to retain the whole fragment with the UI? I saw couple examples where people use an extra Fragment to use the setRetainInstance but.. is there anything wrong not using that extra one??
If there is an issue with using the setRetainInstance why is that? Couldn't find any info in the documentation regarding this.
Even if you use setRetainInstance(true), your Fragment will still recreate its views when you rotate (you will get a call to onDestroyView and then onCreateView). As long as you don't keep references to views past onDestroyView, there will not be any leaks of the old Activity. The best approach would be to explicitly null the references in onDestroyView, but your code in onCreateView would generally overwrite those references anyway.
There are many examples online (including some official ones) where people use a separate fragment (without a view) to retain data. Assuming what I said above is correct, then this is unnecessary (for the sake of preventing leaks). In many cases, you may end up with cleaner code/architecture if you use a separate fragment whose responsibility is just to handle the data and not worry about the UI.
You can check to see if you are leaking Activity contexts after rotating by using Eclipse MAT.
If you are locking your orientation then you should be fine. Otherwise you can end up with memory leaks if you retain widgets that are associated with a particular activity instance.

Categories

Resources