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

Chr*_*ris 159 java android weak-references

我是一名Java开发人员已有2年.

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

dby*_*rne 224

使用WeakReferenceAndroid中并不比普通的旧Java中使用一个什么不同.这是一个很好的指南,它给出了详细的解释:理解弱引用.

你应该考虑使用一个每当你需要一个对象的引用,但你不希望引用要保护的对象从垃圾收集器.一个典型的例子是当内存使用率过高时(通常用它实现WeakHashMap),你想要垃圾收集的缓存.

一定要检查出SoftReferencePhantomReference为好.

编辑:汤姆已经提出了一些关于实现缓存的担忧WeakHashMap.这是一篇文章,列出了问题:WeakHashMap不是缓存!

汤姆是正确的,有过投诉约差NetBeans性能的因WeakHashMap缓存.

我仍然认为这将是一个很好的学习经验,以实现与高速缓存WeakHashMap,然后把它比对与实现自己的手卷缓存SoftReference.在现实世界中,你可能不会使用这两种解决方案,因为它使使用第三方库像更有意义的Apache JCS.

  • 没有!没有!没有!用作缓存的`WeakHashMap`是致命的.条目可以在创建后立即删除.这可能不会在您进行测试时发生,但在使用时可能会发生.值得注意的是,NetBeans可以通过它实现100%有效的CPU停止. (15认同)
  • 断开链接到java.net (4认同)
  • @Tom我已经更新了我的答案.为了公平起见,我在技术上是正确的,缓存通常用`WeakHashMap`实现,即使你是正确的,它是一个糟糕的选择;) (3认同)

김준호*_*김준호 62

[EDIT2]我找到了另一个很好的例子WeakReference.处理位图显示位图中的UI线程页面高效地训练指南,显示WeakReferenceAsyncTask中的一种用法.

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);
            }
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

它说,

对ImageView的WeakReference确保AsyncTask不会阻止ImageView及其引用的任何内容被垃圾回收.当任务完成时,无法保证ImageView仍然存在,因此您还必须检查onPostExecute()中的引用.ImageView可能不再存在,例如,用户导航离开活动或者在任务完成之前发生配置更改.

快乐的编码!


[编辑]WeakReferencefacebook-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());
        }
    };
}
Run Code Online (Sandbox Code Playgroud)

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);
}
Run Code Online (Sandbox Code Playgroud)

最后一件事.我也想知道WeakReferenceAndroid应用程序中的工作示例,我可以在其官方示例应用程序中找到一些示例.但我真的无法理解它们中的一些用法.例如,ThreadSampleShowingBitmaps应用程序WeakReference在其代码中使用,但在运行多个测试之后,我发现get()方法永远不会返回null,因为引用的视图对象在适配器中被回收,而不是垃圾回收.


Sur*_*gch 15

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

如何在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
    }

}
Run Code Online (Sandbox Code Playgroud)

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);
    }
}
Run Code Online (Sandbox Code Playgroud)

笔记

  • 您需要弱引用的原因是垃圾收集器可以在不再需要时处置这些对象.如果两个对象保持对彼此的强引用,则它们不能被垃圾收集.这是内存泄漏.
  • 如果两个对象需要相互引用,则对象A(通常是较短的对象)应该对对象B(通常是较长寿命的对象)具有弱引用,而B对A具有强引用.在上面的示例中,MyClass是A并且AnotherClass是B.
  • 使用a的另一种方法WeakReference是让另一个类实现一个接口.这是在Listener/Observer模式中完成的.

实际的例子


Aks*_*hay 7

"规范化"映射是指将内存中的一个对象实例保存在内存中,而其他所有实例都通过指针或某种机制查找该特定实例.这是弱参考可以帮助的地方.简短的回答是,WeakReference对象可用于创建指向系统中对象的指针,同时仍允许垃圾收集器在超出范围时回收这些对象.例如,如果我有这样的代码:

class Registry {
     private Set registeredObjects = new HashSet();

     public void register(Object object) {
         registeredObjects.add( object );
     }
 }
Run Code Online (Sandbox Code Playgroud)

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

class Registry {
     private Set registeredObjects = new HashSet();

     public void register(Object object) {
         registeredObjects.add( new WeakReference(object) );
     }
 }
Run Code Online (Sandbox Code Playgroud)

然后,当GC想要回收Set中的对象时,它将能够这样做.您可以使用此技术进行缓存,编目等.请参阅下文,以获取有关GC和缓存的更深入讨论的参考.

参考:垃圾收集器和WeakReference