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

我一直是一个Java开发人员2年。

但是我从来没有在我的代码中写过WeakReference。 如何使用WeakReference使我的应用程序更高效,尤其是Android应用程序?

在Android中使用WeakReference与在普通的旧Java中使用WeakReference没有什么不同。 这是一个很好的指导,给出了一个详细的解释: 理解弱引用 。

每当你需要一个对象的引用时,你应该考虑使用一个引用,但是你不希望这个引用保护垃圾收集器的对象。 一个经典的例子就是当内存使用率太高(通常用WeakHashMap实现)时想要被垃圾收集的caching。

一定要检查SoftReferencePhantomReference以及。

编辑:汤姆提出了一些关于用WeakHashMap实现caching的问题。 这里有一篇文章阐述了这个问题: WeakHashMap不是一个caching!

Tom说得对,由于WeakHashMapcaching,Netbeans的性能很差。

我仍然认为用WeakHashMap实现一个caching是一个很好的学习经验,然后将它与SoftReference实现的自己的手动caching进行比较。 在现实世界中,你可能不会使用这些解决scheme,因为使用Apache JCS等第三方库更有意义。

[编辑2]我发现WeakReference另一个很好的例子。 处理位图closures 显示位 图中的UI线程页面有效地训练指南,显示AsyncTask中WeakReference一个用法。

 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); } } } } 

它说,

对ImageView的WeakReference确保AsyncTask不会阻止ImageView及其引用的垃圾收集 。 当任务完成时,不能保证ImageView仍然在附近,因此您还必须检查onPostExecute()中的引用。 例如,如果用户从活动中导航或者在任务完成之前发生configuration更改,则ImageView可能不再存在。

快乐的编码!


[编辑]我从facebook-android-sdkfind了WeakReference一个很好的例子。 ToolTipPopup类不过是一个简单的widget类,它显示了锚视图上方的工具提示。 我抓住了一个截图。

美味的截图

课程非常简单(约200行),值得一看。 在这个类中, WeakReference类用于保存对锚视图的引用,这是非常有意义的,因为即使在工具提示实例的生命期比锚视图长的情况下,锚视图也可以被垃圾收集。

快乐的编码! 🙂


让我分享一个WeakReference类的实例。 这是来自Android框架小部件(称为AutoCompleteTextView的一小段代码段。

总之, 在这个例子中 WeakReference 类用来保存 View 对象来防止内存泄漏 。

我将复制并粘贴PopupDataSetObserver类,它是AutoCompleteTextView的嵌套类。 这很简单,评论很好地解释了这个课程。 快乐的编码! 🙂

  /** * 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用于设置适配器。

  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实例,我可以在其官方示例应用程序中find一些示例。 但我真的不明白其中的一些用法。 例如, ThreadSample和DisplayingBitmaps应用程序在其代码中使用了WeakReference ,但是在运行多个testing之后,我发现get()方法永远不会返回null ,因为引用的视图对象是在适配器中回收的,而不是垃圾回收。

一个“规范化”的映射就是在内存中保存一个有问题的对象的实例,其他所有的实例都通过指针或者其他机制来查找这个特定的实例。 这是弱点参考可以帮助的地方。 简短的回答是, WeakReference对象可以用来创build指向系统中对象的指针,同时仍然允许这些对象一旦超出范围就被垃圾收集器收回。 例如,如果我有这样的代码:

 class Registry { private Set registeredObjects = new HashSet(); public void register(Object object) { registeredObjects.add( object ); } } 

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

 class Registry { private Set registeredObjects = new HashSet(); public void register(Object object) { registeredObjects.add( new WeakReference(object) ); } } 

然后,当GC想要回收Set中的对象时,就可以这样做了。 您可以使用此技术进行caching,编目等。请参阅下面的参考资料,以深入讨论GC和caching。

参考: 垃圾收集器和WeakReference

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

如何在Java和Android中使用WeakReference

您可以执行以下步骤:

  1. 创build一个WeakReferencevariables
  2. 设置弱引用
  3. 使用弱参考

MyClassAnotherClass有一个弱引用。

 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有很强的参考价值。

 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的另一种方法是让另一个类实现一个接口。 这是在听众/观察者模式中完成的 。

实际的例子

  • 静态内部AsyncTask类