If I interpret this article correctly, passing the activity context to AsyncTasks is a potential leak, as the activity might be destroyed while the task is still running.
How do you deal with this in AsyncTasks that are not inner clases and need access to resources or to update the UI?
Additionally, how can you avoid leaking the context if you need references to progress dialogs to dismiss them?
If I understand your question correctly: Java's WeakReference or SoftReference class is a good fit for this type of situation. It will allow you to pass the context to the AsyncTask without preventing the GC from freeing the context if necessary.
The GC is more eager when collecting WeakReferences than it is when collecting SoftReferences.
instead of:
FooTask myFooTask = new FooTask(myContext);
your code would look like:
WeakReference<MyContextClass> myWeakContext = new WeakReference<MyContextClass>(myContext);
FooTask myFooTask = new FooTask(myWeakContext);
and in the AsyncTask instead of:
myContext.someMethod();
your code would look like:
myWeakContext.get().someMethod();
Related
So I read about memory leaks in Android regarding AsyncTask, and in essence, as far as I understood it's when activity is destroyed for some reason but AsyncTask isn't done, so because AsyncTask has a strong reference to Activity, GC can't collect Activity, i.e. can't release it from memory. My question is, if/when AsyncTask finishes its work and is no longer needed, why can't GC collect that referenced Activity then? Why would that be a problem?
Generally, inner classes often outlive their parents which is why the parent class become not eligible for GC. As for AsyncTask, if make your async task inner and provide it with a context of your activity, Android studio will warn that it might cause memory leaks.
This AsyncTask class should be static or leaks might occur (anonymous android.os.AsyncTask) A static field will leak contexts. Non-static inner classes have an implicit reference to their outer class. If that outer class is, for example, a Fragment or Activity, then this reference means that the long-running handler/loader/task will hold a reference to the activity which prevents it from getting garbage collected. Similarly, direct field references to activities and fragments from these long-running instances can cause leaks. ViewModel classes should never point to Views or non-application Contexts.
Non-static inner class outlives its parent. But when you don`t declare it inner that means that you do not have access to parent class members anymore. You can pass in a reference to the Context of your activity but then you run the same risk of a memory leak.
Solution?
A possible solution is to provide a weak reference to your context. Another solution is to cancel your async task in onStop() callback of your activity. Moreover, you can confirm the state of your activity using activityContext.isFinishing(). If the state equals true, simply cancel or return your async task.
A little off topic. Async tasks are a thing of the past, there are other better methods to handle concurrency like RxJava, Kotlin`s coroutines and etc.
I have created a singleton class that performs some DB operation, every activity will call this class, and i need to pass context to it.
This is what each activity will do.
AnalyticsWrapper analyticsWrapper= AnalyticsWrapper.getInstance();
analyticsWrapper.reportView(MainActivity.this)
Now i am little confused about what can go wrong when i am passing activity reference to a singleton class.
I have few questions.
What is the good way of passing context to a long running task.
Is it better if i pass getApplicaitonContex() instead of
MainActivity.this here.
Will it increase memory, when each activity will be passing its context to singleton class, and it can lead to memory leak.
I don't think there is anything wrong using application context for DB Singleton, it will likely outlive Activity so passing Activity Context will leak. I've been passing App Context to Database instances for a long time and it never caused any issue with increasing memory or functionality.
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
I'm fighting with memory leaks now.
Just out of curiosity,
when is mContext, the member of View or Adapter classes, null-cleared?
I couldn't find a part doing such a thing...
EDIT:
I know about GC, but for example,
an ArrayAdapter has mContext, and if Activity has the reference to the ArrayAdapter,
is this a circular reference?
Checking when null variables will get freed is beyond your control. But you can avoid the OOME problems.
As Dmitry said, if you are using Bitmaps, immediately call its recycle() method after use.
This way you can clear the resources you have held and make space for the application to run.
Calling GC is of no use since, even if you call it, it is not sure whether GC will free up your resources.
Also check if you have no memory leak problem in your code. Since this can also lead to OOME. You can check the memory leak problem by using MAT(plugin) for eclipse.
Even if this does not solve your problem, ask us, we'll try to find another solution.
Thank you :)
The context is generally the owning activity, which is managed by Android. It is guaranteed to be active and valid, until the Activity is active. Unless you are doing something tricky or fairly low level, you shouldn't be concerted about mContext in views and adapters.
What you should be concerned about is storing a reference to an activity (such as in a Context mContext or similar field) in a class that can potentially live longer than the activity (service, thread, application class, etc.). This will prevent the system from properly GC-ing the activity and will lead to memory leaks and subtle bugs.
It won't be cleared until garbage collector will get it. In other words - you shouldn't worry about clearing your variables, since they all will be collected by GC if there is no references to them (not instantly, but they will).
But there is one class in Android that causes troubles - Bitmap. If there is memory leaks in your app, first of all - look at bitmap usage. Make sure that you called recycle when you finished with it.
When I use the Android Context within an AsyncTask#doInBackground, is it thread safe? The context is provided via constructor or via getApplicationContext() from a surrounding Activity. This simple questions is asked a lot at stackoverflow and else where but I found not a clear answer?
E.g. in the doInBackground() I use the context in order to Instantiate an DAO class.
#Override
protected Void doInBackground(Void... params) {
ExampleDao dao = new ExampleDao(context);
...
}
I saw several examples doing that in this way, but I cannot image that this is thread-safe, because the context is now accessed by the main tread (UI Thread) and the worker thread.
You can always access the context from different Thread as long as you are not changing something and you only retrieve resources through the context I don't see a problem with Thread-safety.
The problem is that the context will stay in memory and active as long as the Thread runs. This is a good thing for you because you can rely on having a valid context all the time.
The bad thing is that if you pass an Activity as a context all the views and member variables from this activity will also stay in memory and this can lead to a very late garbage collection for a lot of memory, like Waqas suggested.
On thing I would not do from a different Thread is accessing methods from Context subclasses like setTheme() that will affect the currently displayed views.
If you dont need to do anything with Views then always try to use getApplicationContext() which refers to application's context (not activity's context) and may help you to avoid memory leaks while threading or orientation-changes. So, i guess it fits for your needs in AsyncTask too.
Context is not threadsafe actually. But it is ok to pass an instance of application context to write to db for example.