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

2022-08-31 06:42:15

我已经做了2年的Java开发人员。

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


答案 1

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

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

一定要退房,以及。SoftReferencePhantomReference

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

Tom 说得对,有人抱怨 Netbeans 由于缓存而表现不佳。WeakHashMap

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


答案 2

[编辑2]我发现了另一个很好的例子。处理位图“显示位图”有效训练指南中的“UI 线程”页外,显示了 AsyncTask 中的一种用法。WeakReferenceWeakReference

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 的弱引用可确保 AsyncTask 不会阻止 ImageView 及其引用的任何内容被垃圾回收。不能保证 ImageView 在任务完成时仍然存在,因此您还必须在 onPostExecute() 中检查引用。例如,如果用户离开活动,或者在任务完成之前发生配置更改,则 ImageView 可能不再存在。

祝您编码愉快!


[编辑]我从facebook-android-sdk中找到了一个非常好的例子。ToolTipPopup 类只不过是一个简单的小部件类,它在锚点视图上方显示工具提示。我截取了一张截图。WeakReference

scrumptious screenshot

该类非常简单(约200行),值得一看。在该类中,类用于保存对锚点视图的引用,这是非常有意义的,因为即使工具提示实例的生存期长于其锚点视图,也可以对锚点视图进行垃圾回收。WeakReference

祝您编码愉快!:)


让我分享一个阶级的工作例子。这是来自Android框架小部件的一个小代码片段,称为AutoCompleteTextViewWeakReference

简而言之,在此示例中,类用于保存对象以防止内存泄漏WeakReferenceView

我将只复制并粘贴 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应用程序中的工作示例,我可以在其官方示例应用程序中找到一些示例。但我真的无法理解其中一些的用法。例如,ThreadSampleDisplayIngBitmaps 应用程序在其代码中使用,但是在运行了几次测试之后,我发现 get() 方法永远不会返回 ,因为引用的视图对象在适配器中回收,而不是垃圾回收。WeakReferenceWeakReferencenull


推荐