How to Use Weakreference in Java and Android Development

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 ?

  1. 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
    }

  2. If you can referring to an Activity context elsewhere, you can use Weak reference.

  3. While handling bitmap resources in imageview in another thread
    http://developer.android.com/training/displaying-bitmaps/process-bitmap.html

  4. If 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

  5. 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 the function.apply idiom may be null?

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



Leave a reply



Submit