Как использовать WeakReference в разработке Java и Android? - PullRequest
154 голосов
/ 14 июля 2010

Я был разработчиком Java в течение 2 лет.

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

Ответы [ 4 ]

218 голосов
/ 14 июля 2010

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

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

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

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

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

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

60 голосов
/ 12 апреля 2015

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

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

Слабая ссылка на ImageView гарантирует, что AsyncTask не препятствует сборке мусора ImageView и всем, на что он ссылается .Нет гарантии, что 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, поскольку ссылается наобъект просмотра перерабатывается в адаптеры, а не в мусор.

14 голосов
/ 31 октября 2017

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

Как использовать 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
    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 состоит в том, чтобы другой класс реализовывал интерфейс.Это делается в шаблоне «слушатель / наблюдатель» .

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

7 голосов
/ 17 ноября 2016

«Канонизированное» отображение - это когда вы храните один экземпляр рассматриваемого объекта в памяти, а все остальные ищут этот конкретный экземпляр с помощью указателей или некоторого такого механизма.Здесь слабые ссылки могут помочь.Краткий ответ: объекты 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 захочет вернуть объекты из набора, он сможет это сделать.Вы можете использовать эту технику для кэширования, каталогизации и т. Д. См. Ниже ссылки на гораздо более подробные обсуждения GC и кэширования.

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

...