问题
我是一名Java开发人员已有2年了。
但我从来没有在我的代码中写过WeakReference。如何使用WeakReference使我的应用程序更高效,尤其是Android应用程序?
#1 热门回答(205 赞)
在Android中使用aWeakReference
与使用普通旧Java中的一个没什么不同。这是一本很棒的指南,详细解释如下:Understanding Weak References。
每当需要引用对象时,你应该考虑使用它,但是你不希望该引用保护对象免受垃圾收集器的影响。一个典型的例子是当内存使用率过高时你想要被垃圾收集的缓存(通常用WeakHashMap
实现)。
一定要查看SoftReference
和PhantomReference
。
**编辑:**Tom已经提出了一些关于使用WeakHashMap
实现缓存的担忧。这是一篇阐述问题的文章:WeakHashMap is not a cache!
Tom是正确的,因为WeakHashMap
缓存导致Netbeans的性能不佳complaints。
我仍然认为用WeakHashMap
实现缓存是一个很好的学习经验,然后将它与你自己用SoftReference
实现的手动缓存进行比较。在现实世界中,你可能不会使用这些解决方案中的任何一种,因为使用第三方库(如Apache JCS)更有意义。
#2 热门回答(53 赞)
**[EDIT2]**I在8232323451培训指南中找到了另一个很好的例子:WeakReference
.Processing Bitmaps Off the UI Threadpage,显示了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()中的引用。 ImageView可能不再存在,例如,用户导航远离活动或者在任务完成之前发生配置更改。
快乐的编码!
**[编辑]**我发现一个非常好的例子WeakReference
fromfacebook-android-sdk.ToolTipPopupclass只是一个简单的小部件类,它显示了锚点视图上方的工具提示。我抓了一个截图。
这堂课非常简单(约200行),值得一看。在该类中,WeakReference
class用于保持对锚视图的引用,这非常有意义,因为即使工具提示实例比其锚视图更长时间,它也可以对锚视图进行垃圾收集。
快乐的编码! :)
让我分享WeakReference
类的一个工作示例。这是Android框架小部件名为AutoCompleteTextView
的一小段代码片段。
简而言之,WeakReference
类用于保存View
对象以防止这个例子中的memory leak。
我只是复制并粘贴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
的工作示例,我可以在其官方示例应用程序中找到一些示例。但我真的无法理解他们的一些用法。例如,ThreadSample和DisplayingBitmaps应用程序在其代码中使用WeakReference
,但在运行多个测试后,我发现get()方法永远不会返回null
,因为引用的视图对象在适配器中被回收,而不是垃圾回收。
#3 热门回答(10 赞)
其他一些答案似乎不完整或过长。这是一般性答案。
##如何在Java和Android中使用WeakReference
你可以执行以下步骤:
- 创建一个WeakReference变量
- 设置弱参考
- 使用弱引用
##代码
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
强烈引用26470876。
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的另一种方法是让另一个类实现一个接口。这是在Listener / Observer模式中完成的。
##实际例子
- 静态内部AsyncTask类