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


Answers:


229

使用WeakReferenceAndroid中并不比使用一个在普通的Java有什么不同。这是一个很好的指南,提供了详细的解释:了解弱引用

您应该在需要引用对象时考虑使用一个,但是您不希望该引用保护对象免受垃圾收集器的侵害。一个经典的例子是当内存使用率太高(通常使用来实现WeakHashMap)时,您希望对其进行垃圾收集的缓存。

一定要检查出SoftReferencePhantomReference为好。

编辑:汤姆提出了一些有关使用实现缓存的担忧WeakHashMap。这是一篇介绍问题的文章:WeakHashMap不是缓存!

汤姆说对了,有人抱怨WeakHashMap缓存导致Netbeans性能不佳。

我仍然认为,使用实施缓存,WeakHashMap然后将其与使用实施的您自己的手动缓存进行比较,将是一种很好的学习体验SoftReference。在现实世界中,您可能不会使用这两种解决方案中的任何一种,因为使用像Apache JCS这样的第三方库更有意义。


15
没有!没有!没有!WeakHashMap用作缓存是致命的。条目可以在创建后立即删除。测试时可能不会发生这种情况,但在使用时可能会发生。值得注意的是,NetBeans可以由此有效地100%停止CPU。
Tom Hawtin-大头钉

3
@Tom我已经更新了答案。公平地讲,我从技术上来说是正确的,WeakHashMap即使您正确地认为这是一个错误的选择,也经常使用缓存来实现;)
dbyrne 2010年

1
dbyrne的出色回答。谢谢你 我认为克里斯没有理由不接受这个答案。
2012年

@dbyrne我在Activity中使用诸如GridView,ImageView或BaseAdapter之类的对象。在onDestroy方法中,当我完成活动时,是否需要使用Weak / SoftReferences对这个对象执行某些操作?还是系统自动清除此对象的内存?
beni

4
到java.net的链接断开
Suragch

64

[EDIT2]我找到了的另一个很好的例子WeakReference。在“ 有效显示位图”培训指南的“ UI线程”页面上处理位图显示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可能不再存在。

编码愉快!


[编辑]我找到了一个很好的例子WeakReferencefacebook-android-sdk工具提示弹出窗口类不过是一个简单的小部件类,它在锚点视图上方显示工具提示。我截图了。

精美的屏幕截图

该类非常简单(约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);
}

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


1
感谢您提供的出色示例-我真的觉得这应该是该问题的可接受答案。干杯!
Ackshaey Singh

@AckshaeySingh谢谢!:)
김준호

16

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

如何在Java和Android中使用WeakReference

您可以执行以下步骤:

  1. 创建一个 WeakReference变量
  2. 设置弱参考
  3. 使用弱引用

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

笔记

  • 需要弱引用的原因是,以便垃圾收集器可以在不再需要它们时丢弃它们。如果两个对象相互之间保持强引用,则无法对其进行垃圾回收。这是内存泄漏。
  • 如果两个对象需要互相引用,则对象A(通常是寿命较短的对象)对对象B(通常是寿命较长的对象)的引用较弱,而对象B对A的引用较强。在上例中,MyClassA是和AnotherClass为B.
  • 使用a的替代方法WeakReference是让另一个类实现接口。这是在Listener / Observer Pattern中完成的

实际例子


令人困惑的解释。什么是// allow MyClass to get a weak reference to this class void someMethod() { mMyClass = new MyClass(); mMyClass.someMethod(this); }??
likejudo

@likejudo,你是对的。我改进了一些变量和方法命名。现在怎么样
苏拉奇

您需要在调用函数之前检查函数中的weakreference对象本身doSomething是否不在。nullget
Behrouz.M

7

“规范化”映射是在其中将有问题的对象的一个​​实例保留在内存中,而所有其他实例则通过指针或某种类似的机制查找该特定实例。这是弱引用可以提供帮助的地方。简短的答案是,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和缓存进行更深入讨论的参考。

参考:垃圾收集器和WeakReference

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.