Tuesday, 27 December 2016

How to use WeakReference in Java and Android development?

[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 {
private final WeakReference imageViewReference;
private int data = 0;

public BitmapWorkerTask(ImageView imageView) {
// Use a WeakReference to ensure the ImageView can be garbage collected
imageViewReference = new WeakReference(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.

*


* 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 mViewReference;
private PopupDataSetObserver(AutoCompleteTextView view) {
mViewReference = new WeakReference(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  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.

No comments:

Post a Comment

c++ - Does curly brackets matter for empty constructor?

Those brackets declare an empty, inline constructor. In that case, with them, the constructor does exist, it merely does nothing more than t...