如何在Java和Android开发中使用WeakReference?

How to use WeakReference in Java and Android development?

我做Java开发已经有2年了。

但我从未在我的代码中写过一个weakreference。如何使用weakreference使我的应用程序更高效,尤其是Android应用程序?


在Android中使用EDCOX1的0度与使用普通的Java没有什么不同。下面是一个很好的指南,它给出了一个详细的解释:理解薄弱的参考。

当需要对象引用时,应该考虑使用一个,但您不希望该引用保护对象不受垃圾收集器的影响。一个典型的例子是当内存使用率过高时(通常使用WeakHashMap)希望被垃圾收集的缓存。

一定要查看SoftReferencePhantomReference

编辑:Tom对使用WeakHashMap实现缓存提出了一些关注。这里有一篇文章列出了问题:weakhashmap不是一个缓存!

Tom说得对,有人抱怨NetBeans由于WeakHashMap缓存而性能不佳。

我仍然认为使用WeakHashMap实现缓存,然后将其与自己使用SoftReference实现的手动滚动缓存进行比较,这将是一个很好的学习经验。在现实世界中,您可能不会使用这些解决方案中的任何一个,因为使用第三方库(如ApacheJCS)更有意义。


[edit2]我发现了另一个很好的例子:WeakReference。在高效显示位图培训指南中,处理ui线程页外的位图,显示异步任务中WeakReference的一种用法。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
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);
            }
        }
    }
}

它说,

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.

快乐编码!

[编辑]我从facebook android sdk找到了一个很好的WeakReference的例子。toolTipPopup类只是一个简单的小部件类,它在锚定视图上显示工具提示。我拍了一张截图。

scrumptious screenshot

这门课很简单(大约200行),值得一看。在该类中,WeakReference类用于保存对锚视图的引用,这非常有意义,因为即使工具提示实例的寿命比锚视图长,锚视图也可能被垃圾收集。

快乐编码!:)

让我分享一个WeakReference类的工作示例。这是Android框架小部件AutoCompleteTextView的一小段代码。

简而言之,在本例中,WeakReference类用于保存View对象以防止内存泄漏。

我只复制并粘贴PopupDatasetObserver类,它是AutoCompleteTextView的嵌套类。这真的很简单,评论很好地解释了课堂。快乐编码!:)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
    /**
     * 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());
        }
    };
}

设置适配器时使用PopupDataSetObserver

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
    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);
}

最后一件事。我还想知道android应用程序中WeakReference的工作示例,我可以在其官方示例应用程序中找到一些示例。但我真的无法理解其中的一些用法。例如,threadsample和displayingbitmaps应用程序在其代码中使用WeakReference,但在运行了几个测试之后,我发现get()方法从不返回null,因为引用的视图对象在适配器中被回收,而不是被垃圾收集。


其他一些答案似乎不完整或太长。这是一个一般的答案。

如何在Java和Android中使用弱引用

您可以执行以下步骤:

  • 创建一个WeakReference变量
  • 设置弱引用
  • 使用弱引用
  • 代码

    MyClassAnotherClass的引用较弱。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    public class MyClass {

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

        // 2. Set the weak reference
        void someMethod(AnotherClass object) {
            mAnotherClassReference = new WeakReference<>(object);
        }

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

    }

    AnotherClassMyClass有很强的关系。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    public class AnotherClass {

        // strong reference
        MyClass mMyClass;

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

    笔记

    • 需要弱引用的原因是垃圾收集器可以在不再需要对象时对其进行处理。如果两个对象保留了彼此的强引用,那么它们就不能被垃圾收集。这是内存泄漏。
    • 如果两个物体需要相互参照,A物体(一般是较短寿命的物体)应该对B物体(一般是较长寿命的物体)有弱参照,B物体对A有强参照,在上例中,MyClass是A,AnotherClass是B。
    • 使用WeakReference的一个替代方法是让另一个类实现一个接口。这是在侦听器/观察器模式中完成的。

    实例

    • 静态内部异步任务类

    "规范化"映射是指将对象的一个实例保存在内存中,而所有其他实例都通过指针或其他类似机制查找该特定实例。这就是weaks的参考可以帮助的地方。简而言之,weakreference对象可用于创建指向系统中对象的指针,同时还允许垃圾收集器在这些对象超出范围后回收这些对象。例如,如果我有这样的代码:

    1
    2
    3
    4
    5
    6
    7
    class Registry {
         private Set registeredObjects = new HashSet();

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

    GC永远不会回收我注册的任何对象,因为它有一个引用存储在registeredObjects集中。另一方面,如果我这样做:

    1
    2
    3
    4
    5
    6
    7
    class Registry {
         private Set registeredObjects = new HashSet();

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

    然后当GC想要回收集合中的对象时,它将能够这样做。您可以将此技术用于缓存、编目等。有关GC和缓存的更深入讨论的参考,请参见下文。

    参考:垃圾收集器和Weakreference