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

发布于 2024-09-09 01:08:55 字数 112 浏览 0 评论 0原文

我担任 Java 开发人员已有 2 年了。

但我从未在代码中编写过 WeakReference。如何使用 Wea​​kReference 使我的应用程序更加高效,尤其是 Android 应用程序?

I have been a Java developer for 2 years.

But I have never written a WeakReference in my code. How to use WeakReference to make my application more efficient, especially the Android application?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

黯淡〆 2024-09-16 01:08:55

在 Android 中使用 WeakReference 与在普通的旧 Java 中使用弱引用没有任何不同。

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

请务必查看 SoftReferencePhantomReference

编辑: Tom 对使用 WeakHashMap 实现缓存提出了一些担忧。这是一篇列出问题的文章: WeakHashMap 不是缓存!

汤姆是对的,有投诉由于 WeakHashMap 缓存,Netbeans 性能较差。

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

Using a WeakReference in Android isn't any different than using one in plain old Java.

You should think about using one whenever you need a reference to an object, but you don't want that reference to protect the object from the garbage collector. A classic example is a cache that you want to be garbage collected when memory usage gets too high (often implemented with WeakHashMap).

Be sure to check out SoftReference and PhantomReference as well.

EDIT: Tom has raised some concerns over implementing a cache with WeakHashMap. Here is an article laying out the problems: WeakHashMap is not a cache!

Tom is right that there have been complaints about poor Netbeans performance due to WeakHashMap caching.

I still think it would be a good learning experience to implement a cache with WeakHashMap and then compare it against your own hand-rolled cache implemented with SoftReference. In the real world, you probably wouldn't use either of these solutions, since it makes more sense to use a 3rd party library like Apache JCS.

杀手六號 2024-09-16 01:08:55

[EDIT2]我发现了WeakReference的另一个很好的例子。 脱离 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() 中的引用。例如,如果用户离开 Activity 或者在任务完成之前发生配置更改,则 ImageView 可能不再存在。

快乐编码!


[编辑] 我从 facebook- 找到了一个非常好的 WeakReference 示例android-sdkToolTipPopup 类什么都没有而是一个简单的小部件类,在锚视图上方显示工具提示。我截图了。

scrumptious snapshot

该类非常简单(大约 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 的工作示例,我可以在其官方示例应用程序中找到一些示例。但有些用法我实在是看不懂。例如,ThreadSampleDisplayingBitmaps 应用程序在其代码中使用 WeakReference,但在运行多次测试后,我发现 get () 方法永远不会返回 null,因为引用的视图对象在适配器中被回收,而不是被垃圾回收。

[EDIT2] I found another good example of WeakReference. Processing Bitmaps Off the UI Thread page in Displaying Bitmaps Efficiently training guide, shows one usage of WeakReference in 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);
            }
        }
    }
}

It says,

The WeakReference to the ImageView ensures that the AsyncTask does not prevent the ImageView and anything it references from being garbage collected. There’s no guarantee the ImageView is still around when the task finishes, so you must also check the reference in onPostExecute(). The ImageView may no longer exist, if for example, the user navigates away from the activity or if a configuration change happens before the task finishes.

Happy coding!


[EDIT] I found a really good example of WeakReference from facebook-android-sdk. ToolTipPopup class is nothing but a simple widget class that shows tooltip above anchor view. I captured a screenshot.

scrumptious screenshot

The class is really simple(about 200 lines) and worthy to look at. In that class, WeakReference class is used to hold reference to anchor view, which makes perfect sense, because it makes possible for anchor view to be garbage collected even when a tooltip instance lives longer than its anchor view.

Happy coding! :)


Let me share one working example of WeakReference class. It's a little code snippet from Android framework widget called AutoCompleteTextView.

In short, WeakReference class is used to hold View object to prevent memory leak in this example.

I'll just copy-and-paste PopupDataSetObserver class, which is a nested class of AutoCompleteTextView. It's really simple and the comments explains the class well. Happy coding! :)

    /**
     * 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());
        }
    };
}

And the PopupDataSetObserver is used in setting adapter.

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

One last thing. I also wanted to know working example of WeakReference in Android application, and I could find some samples in its official sample applications. But I really couldn't understand some of them's usage. For example, ThreadSample and DisplayingBitmaps applications use WeakReference in its code, but after running several tests, I found out that the get() method never returns null, because referenced view object is recycled in adapters, rather then garbage collected.

电影里的梦 2024-09-16 01:08:55

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

如何在 Java 和 Android 中使用 Wea​​kReference

您可以执行以下步骤:

  1. 创建 WeakReference 变量
  2. 设置弱引用
  3. 使用弱引用

代码

MyClass< /code> 对 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
    }

}

AnotherClassMyClass 有很强的引用。

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 具有强引用。在上面的示例中,MyClass 是 A,AnotherClass 是 B。
  • 使用 WeakReference 的替代方法是让另一个类实现接口。这是在监听器/观察者模式中完成的。

实际示例

Some of the other answers seem incomplete or overly long. Here is a general answer.

How to use WeakReference in Java and Android

You can do the following steps:

  1. Create a WeakReference variable
  2. Set the weak reference
  3. Use the weak reference

Code

MyClass has a weak reference to 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 has a strong reference to 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);
    }
}

Notes

  • The reason you need a weak reference is so that the Garbage Collector can dispose of the objects when they are no longer needed. If two objects retain a strong reference to each other, then they can't be garbage collected. This is a memory leak.
  • If two objects need to reference each other, object A (generally the shorter lived object) should have a weak reference to object B (generally the longer lived object), while B has a strong reference to A. In the example above, MyClass was A and AnotherClass was B.
  • An alternative to using a WeakReference is to have another class implement an interface. This is done in the Listener/Observer Pattern.

Practical example

甲如呢乙后呢 2024-09-16 01:08:55

“规范化”映射是指将相关对象的一个​​实例保留在内存中,而所有其他实例则通过指针或某种此类机制查找该特定实例。这就是弱引用可以发挥作用的地方。
简短的答案是,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

A "canonicalized" mapping is where you keep one instance of the object in question in memory and all others look up that particular instance via pointers or somesuch mechanism. This is where weaks references can help.
The short answer is that WeakReference objects can be used to create pointers to objects in your system while still allowing those objects to be reclaimed by the garbage-collector once they pass out of scope. For example if I had code like this:

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

     public void register(Object object) {
         registeredObjects.add( object );
     }
 }

Any object I register will never be reclaimed by the GC because there is a reference to it stored in the set of registeredObjects. On the other hand if I do this:

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

     public void register(Object object) {
         registeredObjects.add( new WeakReference(object) );
     }
 }

Then when the GC wants to reclaim the objects in the Set it will be able to do so.
You can use this technique for caching, cataloguing, etc. See below for references to much more in-depth discussions of GC and caching.

Ref: Garbage collector and WeakReference

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文