How to use WeakReference in Java and Android development?
Asked Answered
A

4

190

I have been a Java developer for 2 years.

But I have never written a WeakReference in my code. How to use WeakReference to make my application more efficient, especially the Android application?

Amphithecium answered 14/7, 2010 at 3:26 Comment(1)
There might be a diff for Android: #300159Backwards
I
236

Using a WeakReference in Android isn't any different than using one in plain old Java.

You should think about using one whenever you need a reference to an object, but you don't want that reference to protect the object from the garbage collector. A classic example is a cache that you want to be garbage collected when memory usage gets too high (often implemented with WeakHashMap).

Be sure to check out SoftReference and PhantomReference as well.

EDIT: Tom has raised some concerns over implementing a cache with WeakHashMap. Here is an article laying out the problems: WeakHashMap is not a cache!

Tom is right that there have been complaints about poor Netbeans performance due to WeakHashMap caching.

I still think it would be a good learning experience to implement a cache with WeakHashMap and then compare it against your own hand-rolled cache implemented with SoftReference. In the real world, you probably wouldn't use either of these solutions, since it makes more sense to use a 3rd party library like Apache JCS.

Isia answered 14/7, 2010 at 3:37 Comment(10)
No! No! No! WeakHashMap used as a cache is fatal. Entries can be removed as soon as they are created. This probably will not happen when you are testing, but may well when in use. Of note, NetBeans can be brought to an effective 100% CPU stop by this.Overreact
@Tom I've updated my answer. To be fair though, I was technically correct that caches ARE often implemented with WeakHashMap even if you are correct that it is a bad choice ;)Isia
Excellent answer by dbyrne. Thanks for this. I see no reason for the chris not to accept this answer.Lament
@Isia I'm using objects in my Activity like GridView, ImageView or BaseAdapter. In the onDestroy method, when I finish the activity, do I need to do something with this objects using Weak/SoftReferences? Or the system clean automatically this memory of this object?Exsert
@Exsert Instead of answering this in a comment here, I think you would be better off posting this as a new question with more information about your use case. My guess is that you don't need to do anything special, but its impossible to say without more details.Isia
@Isia The first link (understanding...) sometimes just fails to load. Might be worth warning in the answer so people know to try refreshing a few times. Thanks for the great answer.Bowline
broken link to java.netMissie
@dbyrne, To be frank this is not how WeakReferences should be used. The only proper use for WeakReferences is to observe GC runs: https://mcmap.net/q/53428/-what-39-s-the-difference-between-softreference-and-weakreference-in-javaBackwards
@TomHawtin-tackline that is not true! If item is being inserted into WeakHashMap it is definitely strongly referencedCalcifuge
@Calcifuge When a key is being inserted into a WeakHashMap it will, at the start, have a strong reference. But that may be the last use, in which case a correct optimisation which appear to happen in practice is to immediately clear the WeakReference.Overreact
E
74

[EDIT2] I found another good example of WeakReference. Processing Bitmaps Off the UI Thread page in Displaying Bitmaps Efficiently training guide, shows one usage of WeakReference in AsyncTask.

class BitmapWorkerTask extends AsyncTask<Integer, Void, Bitmap> {
    private final WeakReference<ImageView> imageViewReference;
    private int data = 0;

    public BitmapWorkerTask(ImageView imageView) {
        // Use a WeakReference to ensure the ImageView can be garbage collected
        imageViewReference = new WeakReference<ImageView>(imageView);
    }

    // Decode image in background.
    @Override
    protected Bitmap doInBackground(Integer... params) {
        data = params[0];
        return decodeSampledBitmapFromResource(getResources(), data, 100, 100));
    }

    // Once complete, see if ImageView is still around and set bitmap.
    @Override
    protected void onPostExecute(Bitmap bitmap) {
        if (imageViewReference != null && bitmap != null) {
            final ImageView imageView = imageViewReference.get();
            if (imageView != null) {
                imageView.setImageBitmap(bitmap);
            }
        }
    }
}

It says,

The WeakReference to the ImageView ensures that the AsyncTask does not prevent the ImageView and anything it references from being garbage collected. There’s no guarantee the ImageView is still around when the task finishes, so you must also check the reference in onPostExecute(). The ImageView may no longer exist, if for example, the user navigates away from the activity or if a configuration change happens before the task finishes.

Happy coding!


[EDIT] I found a really good example of WeakReference from facebook-android-sdk. ToolTipPopup class is nothing but a simple widget class that shows tooltip above anchor view. I captured a screenshot.

scrumptious screenshot

The class is really simple(about 200 lines) and worthy to look at. In that class, WeakReference class is used to hold reference to anchor view, which makes perfect sense, because it makes possible for anchor view to be garbage collected even when a tooltip instance lives longer than its anchor view.

Happy coding! :)


Let me share one working example of WeakReference class. It's a little code snippet from Android framework widget called AutoCompleteTextView.

In short, WeakReference class is used to hold View object to prevent memory leak in this example.

I'll just copy-and-paste PopupDataSetObserver class, which is a nested class of AutoCompleteTextView. It's really simple and the comments explains the class well. Happy coding! :)

    /**
     * Static inner listener that keeps a WeakReference to the actual AutoCompleteTextView.
     * <p>
     * This way, if adapter has a longer life span than the View, we won't leak the View, instead
     * we will just leak a small Observer with 1 field.
     */
    private static class PopupDataSetObserver extends DataSetObserver {
    private final WeakReference<AutoCompleteTextView> mViewReference;
    private PopupDataSetObserver(AutoCompleteTextView view) {
        mViewReference = new WeakReference<AutoCompleteTextView>(view);
    }
    @Override
    public void onChanged() {
        final AutoCompleteTextView textView = mViewReference.get();
        if (textView != null && textView.mAdapter != null) {
            // If the popup is not showing already, showing it will cause
            // the list of data set observers attached to the adapter to
            // change. We can't do it from here, because we are in the middle
            // of iterating through the list of observers.
            textView.post(updateRunnable);
        }
    }

    private final Runnable updateRunnable = new Runnable() {
        @Override
        public void run() {
            final AutoCompleteTextView textView = mViewReference.get();
            if (textView == null) {
                return;
            }
            final ListAdapter adapter = textView.mAdapter;
            if (adapter == null) {
                return;
            }
            textView.updateDropDownForFilter(adapter.getCount());
        }
    };
}

And the PopupDataSetObserver is used in setting adapter.

    public <T extends ListAdapter & Filterable> void setAdapter(T adapter) {
    if (mObserver == null) {
        mObserver = new PopupDataSetObserver(this);
    } else if (mAdapter != null) {
        mAdapter.unregisterDataSetObserver(mObserver);
    }
    mAdapter = adapter;
    if (mAdapter != null) {
        //noinspection unchecked
        mFilter = ((Filterable) mAdapter).getFilter();
        adapter.registerDataSetObserver(mObserver);
    } else {
        mFilter = null;
    }
    mPopup.setAdapter(mAdapter);
}

One last thing. I also wanted to know working example of WeakReference in Android application, and I could find some samples in its official sample applications. But I really couldn't understand some of them's usage. For example, ThreadSample and DisplayingBitmaps applications use WeakReference in its code, but after running several tests, I found out that the get() method never returns null, because referenced view object is recycled in adapters, rather then garbage collected.

Eyot answered 12/4, 2015 at 14:51 Comment(2)
Thanks for the great examples - I really feel that this should be the accepted answer for the question. Cheers!Emeryemesis
@AckshaeySingh Thanks! :)Fireresistant
M
19

Some of the other answers seem incomplete or overly long. Here is a general answer.

How to use WeakReference in Java and Android

You can do the following steps:

  1. Create a WeakReference variable
  2. Set the weak reference
  3. Use the weak reference

Code

MyClass has a weak reference to AnotherClass.

public class MyClass {

    // 1. Create a WeakReference variable
    private WeakReference<AnotherClass> mAnotherClassReference;

    // 2. Set the weak reference (nothing special about the method name)
    void setWeakReference(AnotherClass anotherClass) {
        mAnotherClassReference = new WeakReference<>(anotherClass);
    }

    // 3. Use the weak reference
    void doSomething() {
        AnotherClass anotherClass = mAnotherClassReference.get();
        if (anotherClass == null) return;
        // do something with anotherClass
    }

}

AnotherClass has a strong reference to MyClass.

public class AnotherClass {
    
    // strong reference
    MyClass mMyClass;
    
    // allow MyClass to get a weak reference to this class
    void someMethod() {
        mMyClass = new MyClass();
        mMyClass.setWeakReference(this);
    }
}

Notes

  • The reason you need a weak reference is so that the Garbage Collector can dispose of the objects when they are no longer needed. If two objects retain a strong reference to each other, then they can't be garbage collected. This is a memory leak.
  • If two objects need to reference each other, object A (generally the shorter lived object) should have a weak reference to object B (generally the longer lived object), while B has a strong reference to A. In the example above, MyClass was A and AnotherClass was B.
  • An alternative to using a WeakReference is to have another class implement an interface. This is done in the Listener/Observer Pattern.

Practical example

Missie answered 31/10, 2017 at 3:36 Comment(3)
confusing explanation. what is // allow MyClass to get a weak reference to this class void someMethod() { mMyClass = new MyClass(); mMyClass.someMethod(this); } ??Kiona
@likejudo, You're right. I improved some of the variable and method naming. How is it now?Missie
you need to check the weakreference object itself in doSomething function to not be null before calling get function.Dynamo
T
9

A "canonicalized" mapping is where you keep one instance of the object in question in memory and all others look up that particular instance via pointers or somesuch mechanism. This is where weaks references can help. The short answer is that WeakReference objects can be used to create pointers to objects in your system while still allowing those objects to be reclaimed by the garbage-collector once they pass out of scope. For example if I had code like this:

class Registry {
     private Set registeredObjects = new HashSet();

     public void register(Object object) {
         registeredObjects.add( object );
     }
 }

Any object I register will never be reclaimed by the GC because there is a reference to it stored in the set of registeredObjects. On the other hand if I do this:

class Registry {
     private Set registeredObjects = new HashSet();

     public void register(Object object) {
         registeredObjects.add( new WeakReference(object) );
     }
 }

Then when the GC wants to reclaim the objects in the Set it will be able to do so. You can use this technique for caching, cataloguing, etc. See below for references to much more in-depth discussions of GC and caching.

Ref: Garbage collector and WeakReference

Trow answered 17/11, 2016 at 9:32 Comment(1)
As discussed above, it might not be a good idea to use for cachingHermelindahermeneutic

© 2022 - 2024 — McMap. All rights reserved.