如何在Java和Android开发中使用WeakReference?
我一直是一个Java开发人员2年。
但是我从来没有在我的代码中写过WeakReference。 如何使用WeakReference使我的应用程序更高效,尤其是Android应用程序?
在Android中使用WeakReference
与在普通的旧Java中使用WeakReference
没有什么不同。 这是一个很好的指导,给出了一个详细的解释: 理解弱引用 。
每当你需要一个对象的引用时,你应该考虑使用一个引用,但是你不希望这个引用保护垃圾收集器的对象。 一个经典的例子就是当内存使用率太高(通常用WeakHashMap
实现)时想要被垃圾收集的caching。
一定要检查SoftReference
和PhantomReference
以及。
编辑:汤姆提出了一些关于用WeakHashMap
实现caching的问题。 这里有一篇文章阐述了这个问题: WeakHashMap不是一个caching!
Tom说得对,由于WeakHashMap
caching,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
您可以执行以下步骤:
- 创build一个
WeakReference
variables - 设置弱引用
- 使用弱参考
码
MyClass
对AnotherClass
有一个弱引用。
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 } }
AnotherClass
对MyClass
有很强的参考价值。
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类