我已经做了 2 年的 Java 开发人员。
但是我从来没有在我的代码中写过 WeakReference。如何使用 WeakReference 使我的应用程序更高效,尤其是 Android 应用程序?
我已经做了 2 年的 Java 开发人员。
但是我从来没有在我的代码中写过 WeakReference。如何使用 WeakReference 使我的应用程序更高效,尤其是 Android 应用程序?
在 Android 中使用 aWeakReference
与在普通的旧 Java 中使用 a 没有什么不同。
您应该考虑在需要引用对象时使用一个,但您不希望该引用保护对象免受垃圾收集器的侵害。一个典型的例子是一个缓存,当内存使用率太高时你希望它被垃圾回收(通常用 实现WeakHashMap
)。
一定要检查SoftReference
一下PhantomReference
。
编辑: Tom 对使用WeakHashMap
. 这是一篇阐述问题的文章:WeakHashMap 不是缓存!
Tom 是对的,有人抱怨由于WeakHashMap
缓存导致 Netbeans 性能不佳。
我仍然认为WeakHashMap
用SoftReference
. 在现实世界中,您可能不会使用这些解决方案中的任何一个,因为使用像Apache JCS这样的 3rd 方库更有意义。
[EDIT2]我发现了另一个很好的例子WeakReference
。Processing Bitmaps Off the UI Thread page in Displaying Bitmaps Efficiently training guide,展示WeakReference
了 AsyncTask 中的一种用法。
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
我从facebook-android-sdk中找到了一个非常好的例子。ToolTipPopup类不过是一个简单的小部件类,它在锚视图上方显示工具提示。我截图了。
这个类非常简单(大约 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);
}
最后一件事。我还想知道WeakReference
Android 应用程序中的工作示例,我可以在其官方示例应用程序中找到一些示例。但我真的无法理解其中一些的用法。例如,ThreadSample和DisplayingBitmaps应用程序WeakReference
在其代码中使用,但经过多次测试,我发现 get() 方法永远不会返回null
,因为引用的视图对象在适配器中被回收,而不是垃圾收集。
其他一些答案似乎不完整或过长。这是一个一般性的答案。
您可以执行以下步骤:
WeakReference
变量MyClass
对 的引用很弱AnotherClass
。
public class MyClass {
// 1. Create a WeakReference variable
private WeakReference<AnotherClass> mAnotherClassReference;
// 2. Set the weak reference (nothing special about the method name)
void setWeakReference(AnotherClass anotherClass) {
mAnotherClassReference = new WeakReference<>(anotherClass);
}
// 3. Use the weak reference
void doSomething() {
AnotherClass anotherClass = mAnotherClassReference.get();
if (anotherClass == null) return;
// do something with anotherClass
}
}
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.setWeakReference(this);
}
}
MyClass
A并且AnotherClass
是B。WeakReference
是让另一个类实现一个接口。这是在Listener/Observer Pattern中完成的。“规范化”映射是您将所讨论对象的一个实例保存在内存中,而所有其他实例通过指针或某种此类机制查找该特定实例。这就是弱引用可以提供帮助的地方。简短的回答是WeakReference对象可用于创建指向系统中对象的指针,同时仍然允许垃圾收集器在它们超出范围后回收这些对象。例如,如果我有这样的代码:
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 中的对象时,它将能够这样做。您可以将这种技术用于缓存、编目等。请参阅下文以获取有关 GC 和缓存的更深入讨论的参考资料。