Как использовать WeakReference в разработке Java и Android?
Я был разработчиком Java в течение 2 лет.
Но я никогда не писал WeakReference в своем коде. Как использовать WeakReference, чтобы сделать мое приложение более эффективным, особенно приложение Android?
4 ответа
Используя WeakReference
в Android ничем не отличается от использования в простой старой Java. Вот отличное руководство, которое дает подробное объяснение: Понимание слабых ссылок.
Вам следует подумать об его использовании всякий раз, когда вам нужна ссылка на объект, но вы не хотите, чтобы эта ссылка защищала объект от сборщика мусора. Классическим примером является кэш, который вы хотите собирать мусором, когда использование памяти становится слишком высоким (часто реализуется с WeakHashMap
).
Не забудьте проверить SoftReference
а также PhantomReference
также.
РЕДАКТИРОВАТЬ: Том поднял некоторые опасения по поводу реализации кэша с WeakHashMap
, Вот статья с изложением проблем: WeakHashMap - это не кеш!
Том прав, что были жалобы на плохую производительность Netbeans из-за WeakHashMap
кэширование.
Я до сих пор думаю, что было бы полезно изучить кэш с WeakHashMap
а затем сравните его с собственным кешем, реализованным вручную SoftReference
, В реальном мире вы, вероятно, не будете использовать ни одно из этих решений, поскольку более разумно использовать стороннюю библиотеку, такую как Apache JCS.
[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 может больше не существовать, если, например, пользователь отходит от действия или если изменение конфигурации происходит до завершения задачи.
Удачного кодирования!
[РЕДАКТИРОВАТЬ] Я нашел действительно хороший примерWeakReference
с Facebook-Android-SDK. Класс ToolTipPopup- это не что иное, как простой класс виджетов, который показывает всплывающую подсказку над видом привязки. Я сделал снимок экрана.
Класс действительно прост (около 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 и Displaying Bitmaps используют WeakReference
в своем коде, но после выполнения нескольких тестов я обнаружил, что метод get() никогда не возвращается null
потому что объект ссылочного представления перерабатывается в адаптерах, а не в сборщике мусора.
Некоторые другие ответы кажутся неполными или слишком длинными. Вот общий ответ.
Как использовать 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
был А иAnotherClass
был Б. - Альтернатива использованию
WeakReference
должен иметь другой класс, реализующий интерфейс. Это сделано в Шаблоне Слушателя / Наблюдателя.
Практический пример
"Канонизированное" отображение - это когда вы сохраняете один экземпляр рассматриваемого объекта в памяти, а все остальные ищут этот конкретный экземпляр с помощью указателей или некоторого такого механизма. Здесь слабые ссылки могут помочь. Краткий ответ заключается в том, что объекты 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