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

Я занимаюсь Java-разработкой 2 года.

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


person Chris    schedule 14.07.2010    source источник
comment
Для Android может быть разница: stackoverflow.com/questions/299659/   -  person Pacerier    schedule 19.09.2017


Ответы (4)


Использование WeakReference в Android ничем не отличается от использования его в простой старой Java.

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

Не забудьте также проверить SoftReference и PhantomReference.

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

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

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

person dbyrne    schedule 14.07.2010
comment
Нет! Нет! Нет! WeakHashMap, используемый в качестве кеша, является фатальным. Записи могут быть удалены, как только они будут созданы. Вероятно, этого не произойдет, когда вы тестируете, но вполне может при использовании. Следует отметить, что благодаря этому NetBeans может быть эффективно остановлен на 100%. - person Tom Hawtin - tackline; 14.07.2010
comment
@Tom Я обновил свой ответ. Честно говоря, я был технически прав, что кеши часто реализуются с WeakHashMap, даже если вы правы, что это плохой выбор;) - person dbyrne; 14.07.2010
comment
Отличный ответ dbyrne. Спасибо за это. Я не вижу причин для Криса не принять этот ответ. - person san; 22.02.2012
comment
@dbyrne Я использую объекты в своей деятельности, такие как GridView, ImageView или BaseAdapter. В методе onDestroy, когда я заканчиваю действие, мне нужно что-то делать с этими объектами с помощью Weak / SoftReferences? Или система автоматически очищает эту память этого объекта? - person beni; 20.02.2013
comment
@beni Вместо того, чтобы отвечать на это в комментарии здесь, я думаю, вам было бы лучше опубликовать это как новый вопрос с дополнительной информацией о вашем варианте использования. Полагаю, что ничего особенного делать не нужно, но без подробностей об этом сказать невозможно. - person dbyrne; 21.02.2013
comment
@dbyrne Первая ссылка (понимание ...) иногда просто не загружается. Возможно, стоит предупредить в ответ, чтобы люди знали, что нужно попробовать освежиться несколько раз. Спасибо за отличный ответ. - person yarian; 31.03.2015
comment
неработающая ссылка на java.net - person Suragch; 07.06.2017
comment
@dbyrne, Откровенно говоря, WeakReferences использовать не так. Единственное правильное использование WeakReferences - наблюдение за запуском GC: stackoverflow.com/a/46291143/632951 - person Pacerier; 19.09.2017

[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 и всего, на что он ссылается. Нет никакой гарантии, что ImageView все еще существует после завершения задачи, поэтому вы также должны проверить ссылку в onPostExecute (). ImageView может больше не существовать, если, например, пользователь уходит от операции или если изменение конфигурации происходит до завершения задачи.

Удачного кодирования!


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

потрясающий снимок экрана

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

person 김준호    schedule 12.04.2015
comment
Спасибо за отличные примеры - я действительно считаю, что это должен быть принятый ответ на вопрос. Ваше здоровье! - person Ackshaey Singh; 04.04.2016
comment
@AckshaeySingh Спасибо! :) - person 김준호; 05.04.2016

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

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

Вы можете сделать следующие шаги:

  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. В приведенном выше примере MyClass был А и AnotherClass был Б.
  • Альтернативой использованию WeakReference является другой класс, реализующий интерфейс. Это делается в шаблоне слушателя / наблюдателя.

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

person Suragch    schedule 31.10.2017
comment
запутанное объяснение. что такое // allow MyClass to get a weak reference to this class void someMethod() { mMyClass = new MyClass(); mMyClass.someMethod(this); } ?? - person likejudo; 03.11.2019
comment
@likejudo, ты прав. Я улучшил некоторые имена переменных и методов. Как сейчас? - person Suragch; 04.11.2019
comment
вам нужно проверить, чтобы сам объект weakreference в функции doSomething не был null перед вызовом функции get. - person Behrouz.M; 12.05.2020

«Каноническое» отображение - это когда вы храните один экземпляр рассматриваемого объекта в памяти, а все остальные ищут этот конкретный экземпляр с помощью указателей или другого подобного механизма. Здесь могут помочь слабые ссылки. Короткий ответ заключается в том, что объекты WeakReference можно использовать для создания указателей на объекты в вашей системе, в то же время позволяя этим объектам быть возвращенными сборщиком мусора, когда они выходят из сфера. Например, если бы у меня был такой код:

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

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

Любой зарегистрированный мной объект никогда не будет возвращен сборщиком мусора, потому что на него есть ссылка, хранящаяся в наборе registeredObjects. С другой стороны, если я сделаю это:

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

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

Затем, когда GC захочет вернуть объекты в Set, он сможет это сделать. Вы можете использовать этот метод для кэширования, каталогизации и т. Д. См. Ниже ссылки на более подробные обсуждения GC и кеширования.

Ссылка: Сборщик мусора и WeakReference

person Akshay    schedule 17.11.2016