Как использовать WeakReference в разработке Java и Android?

Я был разработчиком Java уже 2 года.

Но я никогда не писал WeakReference в своем коде. Как использовать WeakReference, чтобы повысить эффективность моего приложения, особенно приложения Android?

Ответ 1

Использование WeakReference в Android не отличается от использования в простой старой Java. Вот отличный справочник, который дает подробное объяснение: Понимание слабых ссылок.

Вы должны думать об использовании одного, когда вам нужна ссылка на объект, но вы не хотите, чтобы эта ссылка защищала объект от сборщика мусора. Классическим примером является кеш, который вы хотите собрать мусором, когда использование памяти становится слишком высоким (часто реализуется с помощью WeakHashMap).

Обязательно проверьте SoftReference и PhantomReference.

РЕДАКТИРОВАТЬ: Том поднял некоторые проблемы с реализацией кэша с помощью WeakHashMap. Вот статья, в которой излагаются проблемы: WeakHashMap не является кешем!

Том прав, что были жалобы относительно плохой производительности Netbeans из-за кеширования WeakHashMap.

Я все еще думаю, что было бы хорошим опытом для внедрения кэша с WeakHashMap, а затем сравнить его с вашим собственным ручным кэшем, реализованным с помощью SoftReference. В реальном мире вы, вероятно, не использовали бы ни одно из этих решений, поскольку имеет смысл использовать стороннюю библиотеку, например Apache JCS.

Ответ 2

[EDIT2] Я нашел еще один хороший пример WeakReference. Обработка битмапов с страницей пользовательского интерфейса в Отображение битмапов Эффективно руководство по обучению показывает одно использование 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);
            }
        }
    }
}

В нем говорится:

Функция WeakReference для ImageView гарантирует, что AsyncTask не предотвратит отображение ImageView и все, что он ссылается, на сбор мусора. Theres не гарантирует, что ImageView все еще вокруг, когда задача заканчивается, поэтому вы также должны проверить ссылку в onPostExecute(). ImageView больше не может существовать, если, например, пользователь переходит от действия или если изменение конфигурации происходит до завершения задачи.

Счастливое кодирование!


[EDIT] Я нашел действительно хороший пример WeakReference из facebook-android-sdk. ToolTipPopup класс - не что иное, как простой класс виджетов, который показывает всплывающую подсказку над представлением привязки. Я снял снимок экрана.

scrumptious screenshot

Класс действительно прост (около 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, поскольку ссылочный объект представления перерабатывается в адаптерах, а не собирает мусор.

Ответ 3

"Канонизированное" отображение - это то, где вы храните один экземпляр рассматриваемого объекта в памяти, а все остальные просматривают этот конкретный экземпляр через указатели или какой-то механизм. Здесь могут помочь ссылки слабых сторон. Короткий ответ заключается в том, что объекты 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

Ответ 4

Некоторые из других ответов кажутся неполными или слишком длинными. Вот общий ответ.

Как использовать WeakReference в Java и Android

Вы можете выполнить следующие действия:

  • Создайте переменную WeakReference
  • Установить слабую ссылку
  • Используйте слабую ссылку

код

MyClass имеет слабую ссылку на AnotherClass.

public class MyClass {

    // 1. Create a WeakReference variable
    private WeakReference<AnotherClass> mAnotherClassReference;

    // 2. Set the weak reference
    void someMethod(AnotherClass object) {
        mAnotherClassReference = new WeakReference<>(object);
    }

    // 3. Use the weak reference
    void anotherMethod() {
        AnotherClass object = mAnotherClassReference.get();
        if (object == null) return;
        // do something with the object
    }

}

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.someMethod(this);
    }
}

Примечания

  • Причина, по которой вам нужна слабая ссылка, заключается в том, что сборщик мусора может распоряжаться объектами, когда они больше не нужны. Если два объекта сохраняют сильную ссылку друг на друга, то они не могут быть собраны мусором. Это утечка памяти.
  • Если два объекта должны ссылаться друг на друга, объект A (как правило, более короткоживущий объект) должен иметь слабую ссылку на объект B (как правило, более длинный объект), а B имеет сильную ссылку на A. В приведенном выше примере, MyClass было A и AnotherClass было B.
  • Альтернативой использованию WeakReference является использование другого класса интерфейса. Это делается в шаблоне слушателя/наблюдателя.

Практический пример