Android Asyntask: Use weak reference for context to avoid device rotate screen
Somewhere in your AsyncTask
you'll want to pass in your activity. Then you'll save that reference in a weak reference. Then you can dereference and use it again in onPostExecute
.
Class member:
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
}
why use WeakReference on android Listeners?
A weak reference, simply put, is a reference that isn't strong enough
to force an object to remain in memory.
The authors of this code most likely wanted to avoid leaking of the Activity context if the RequestCustomData
object could outlive the Activity itself.
I recommend Romain Guy's post on this topic as well as several specific cases to avoid:
- inner classes and leaks
- threads and leaks
Android WeakReference
If I see your code you create strong reference again after get weak reference value in Context nContext
variable. So need to follow below process if you want to implement weak reference concept :-
define global class variable :-
private final WeakReference< Context > nContext;
set value in global variable through passing from another area
nContext = new WeakReference<Context>(nContext);
and then
if (nContext.get() != null)
// code
}
https://medium.com/google-developer-experts/weakreference-in-android-dd1e66b9be9d
Weak reference instead of getActivity() (Android avoid memory leak)?
It is totally feasible. For example you have this pseudocode code:
public class MainActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
new DownloadTask().execute();
}
public void showInfo() {
}
class DownloadTask extends AsyncTask<Void, Void, Void> {
@Override
protected Void doInBackground(Void... params) {
return null;
}
@Override
protected void onPostExecute(Void data) {
// we can call showInfo() activity because Asynctask hold an implicit reference to activity
showInfo();
}
}
}
On above code, there is a situation will caused memory leak.
Here is the explanation:
When you create DownloadTask
as above example, java call DownloadTask
is an inner class. An inner class will implicit holds a reference to outer class, in this case is MainActivity
. Moreover, when you start an asynctask, that asynctask will be held by system until it finish. For example, you download takes 30 seconds. In that 30 seconds, you rotate your device. When you rotate your device, MainActivity
is re-created and often old activity will be destroyed. But in this case old activity isn't destroyed because the old MainActivity
instance is held by DownloadTask
and DownloadTask
is hold by system. You will leak one activity instance.
For fixing this, you should change above code to:
public class MainActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
new DownloadTask(this).execute();
}
public void showInfo() {
}
}
class DownloadTask extends AsyncTask<Void, Void, Void> {
WeakReference<MainActivity> mainActivityWeakReference;
public DownloadTask(MainActivity activity) {
mainActivityWeakReference = new WeakReference<MainActivity>(activity);
}
@Override
protected Void doInBackground(Void... params) {
return null;
}
@Override
protected void onPostExecute(Void data) {
if (mainActivityWeakReference.get() != null) {
mainActivityWeakReference.get().showInfo();
}
}
}
In this case, when new MainActivity
is created, the old one isn't held by DownloadTask
(due to weak reference attribute), so the old one will be destroyed by Android Garbage Collector in future. You also should to check every time you use a weak reference object, because you don't know exactly when GC will destroyed those object.
Here is my own blog about another situation of memory leak. Memory leak when using static inner class
Hope this help.
Android: passing WeakReference as a parameter
No, your ImageView in Obj_B will not be a WeakReference. A WeakReference allows you to store a reference to an object in such a way that if that object has no other "strong" references anywhere, it will be garbage collected. By removing the WeakReference wrapper in Obj_B, you're now taking the object that your WeakReference was managing and storing your own strong reference to it.
Issue about weakreferences
In Java, first thing to understand is Garbage Collector reclaims memory from objects which are eligible for garbage collection
Question is how is the eligibility defined ?
eligibility is decided based upon which kind of references are pointing to that object.
Why we need Weak Reference ?
If you create a Strong reference to an object, the object cannot be garbage collected. Whereas, A weak reference, simply put, is a reference that isn't strong enough to force an object to remain in memory. Weak references allow you to leverage the garbage collector's ability to determine reachability for you, so you don't have to do it yourself.
Issue here
Weak reference isn't strong enough to prevent garbage collection, so you may find (if there are no strong references to the class) that myWeakClassX.get() suddenly starts returning null.
What is the other option ?
Soft Reference
You use a SoftReference when you want the referenced object to stay alive until the host process is running low on memory. The object will not be eligible for collection until the collector needs to free memory. Loosely stated, binding a SoftReference means, "Pin the object until you can't anymore."
This way myWeakClassX.get() will not be null.
Examples of where we can use ?
In any secondary threads where you create a reference to the activity.
WeakReference weakActivity;
//In AsyncTask onPostExecute Method
Activity activity = weakActivity.get();
if (activity != null) {
// do your stuff with activity here
}If you can referring to an Activity context elsewhere, you can use Weak reference.
While handling bitmap resources in imageview in another thread
http://developer.android.com/training/displaying-bitmaps/process-bitmap.htmlIf you are creating any Hashmap or any widget to hold any data, you can use Weak reference. http://developer.android.com/reference/java/util/WeakHashMap.html
Usage is unlimited. It is up to the developer to utilize it at right places.
A rare usage of WeakReference?
Note that a method like
// multiple instantiation is not a problem;
private static MyAttributeConverter instance() {
if (instance == null) {
instance = new MyAttributeConverter();
}
return instance;
}
is not thread safe, as it bears two reads of the instance
field; each of them may perceive updates made by other threads or not. This implies that the first read in instance == null
may perceive a newer value written by another thread whereas the second in return instance;
could evaluate to the previous value, i.e. null
. So this method could return null
when more than one thread is executing it concurrently. This is a rare corner case, still, this method is not safe. You’d need a local variable to ensure that the test and the return statement use the same value.
// multiple instantiation is not a problem;
private static MyAttributeConverter instance() {
MyAttributeConverter current = instance;
if (current == null) {
instance = current = new MyAttributeConverter();
}
return current;
}
This still is only safe when MyAttributeConverter
is immutable using only final
fields. Otherwise, a thread may return an instance created by another thread in an incompletely constructed state.
You can use the simple way to make it safe without those constraints:
private static final MyAttributeConverter instance = new MyAttributeConverter();
private static MyAttributeConverter instance() {
return instance;
}
This still is lazy as class initialization only happens on one of the specified triggers, i.e. the first invocation of the method instance()
.
Your usage of WeakReference
is subject to the same problems. Further, it’s not clear why you resort to a recursive invocation of your method at two points where you already have the required argument in a local variable.
A correct implementation can be far simpler:
private static WeakReference<MyAttributeConverter> reference;
public static <R> R applyInstance(
Function<? super MyAttributeConverter, ? extends R> function) {
WeakReference<MyAttributeConverter> r = reference;
MyAttributeConverter referent = r != null? r.get(): null;
if (referent == null) {
referent = new MyAttributeConverter();
reference = new WeakReference<>(referent);
}
return function.apply(referent);
}
But before you are going to use it, you should reconsider whether the complicated code is worth the effort. The fact that you are accepting the need to reconstruct the object when it has been garbage collected, even potentially constructing multiple instances on concurrent invocations, suggest that you know that the construction will be cheap. When the construction is cheap, you probably don’t need to cache an instance of it at all.
Just consider
public static <R> R applyInstance(
Function<? super MyAttributeConverter, ? extends R> function) {
return function.apply(new MyAttributeConverter());
}
It’s at least worth trying, measuring the application’s performance and comparing it with the other approaches.
On the other hand, it doesn’t look like the instance was occupying a significant amount of memory nor holding non-memory resources. As otherwise, you were more worried about the possibility of multiple instances flying around. So the other variant worth trying and comparing, is the one shown above using a static final
field with lazy class initialization and no opportunity to garbage collect that small object.
One last clarification. You asked
Is there any chance that
reference.get()
inside thefunction.apply
idiom may benull
?
Since there is no reference.get()
invocation inside the evaluation of function.apply
, there is no chance that such an invocation may evaluate to null
at this point. The function receives a strong reference and since the calling code ensured that this strong reference is not null
, it will never become null
during the invocation of the apply
method.
Generally, the garbage collector will never alter the application state in a way that code using strong references will notice a difference (letting the availability of more memory aside).
But since you asked specifically about reference.get()
, a garbage collector may collect an object after its last use, regardless of method executions or local scopes. So the referent could get collected during the execution of the apply
method when this method does not use the object anymore. Runtime optimizations may allow this to happen earlier than you might guess by looking at the source code, because what may look like an object use (e.g. a field read) may not use the object at runtime (e.g. because that value is already held in a CPU register, eliminating the need to access the object’s memory). As said, all without altering the method’s behavior.
So a hypothetical reference.get()
during the execution of the apply
method could in principle evaluate to null
, but there is no reason for concern, as said, the behavior of the apply
method does not change. The JVM will retain the object’s memory as long as needed for ensuring this correct method execution.
But that explanation was just for completeness. As said, you should not use weak nor soft references for objects not holding expensive resources.
Best practice: weak reference to activity in static method
No, it doesn't make a difference. Garbage collection in Java works on the idea of GC roots. If a variable is a GC root or references by a GC root (including transitively) it cannot be garbage collected. Parameters to a function are a GC root- until the function returns none of its parameters can be collected. Since Activity is a parameter to your function, it will be uncollectable as long as that function is in the call stack. Using a WeakReference won't speed it up.
Threads and AsyncTasks (which are just wrappers around Thread really) are slightly different. Every running thread is also a GC root. But threads can have a long lifetime and exist beyond the lifecycle of the object. Here, using a WeakReference does possibly help because there isn't another reason it needs to be kept around (like the parameter in your sample).
Your example 2 is a bit better, it isn't blatantly unnecessary. But I question why its needed. In general when doing a Thread the pattern should be:
run() {
do_async_work()
update_ui()
}
update_ui() {
Activity activity = weakReference.get()
if(activity == null) {
return
}
//update the UI
}
Doing it like this will prevent a lot of problems like needing to check the weak reference a dozen times.
Related Topics
Why Can Not I Add Two Bytes and Get an Int and I Can Add Two Final Bytes Get a Byte
How to Get Eclipse to Use a Different Compiler Version for Java
Right Way to Implement Equals Contract
Is Addition of Byte Converts to Int Because of Java Language Rules or Because of Jvm
Java, Find Intersection of Two Arrays
How Big Is an Object Reference in Java and Precisely What Information Does It Contain
Is Default No-Args Constructor Mandatory for Gson
How to Make a Jtable Non-Editable
Java Output Formatting for Strings
Why Doesn't Java Throw an Exception When Dividing by 0.0
Java.Sql.Sqlexception: No Suitable Driver Found for Jdbc:Microsoft:Sqlserver
Meaning of the Import Statement in a Java File
When/Why to Call System.Out.Flush() in Java
How to Get Data from Each Dynamically Created Edittext in Android