Відповіді:
Використання WeakReference
в Android не відрізняється від використання в звичайній старій Java. Ось чудовий посібник, який дає детальне пояснення: Розуміння слабких посилань .
Вам слід подумати про використання його кожного разу, коли вам потрібна посилання на об'єкт, але ви не хочете, щоб ця посилання захищала об'єкт від сміттєзбірника. Класичний приклад - кеш, який потрібно збирати сміттям, коли використання пам'яті стає надто високим (часто реалізується за допомогою WeakHashMap
).
Не забудьте перевірити SoftReference
і PhantomReference
.
EDIT: Том висловив деякі занепокоєння щодо впровадження кешу WeakHashMap
. Ось стаття, що викладає проблеми: WeakHashMap - це не кеш!
Том прав, що були скарги на погану продуктивність Netbeans через WeakHashMap
кешування.
Я все ще думаю, що було б добре вивчити кеш, WeakHashMap
а потім порівняти його з власним кешованим кешем, реалізованим із SoftReference
. У реальному світі ви, мабуть, не скористалися б жодним із цих рішень, оскільки має сенс використовувати сторонню бібліотеку, як Apache JCS .
WeakHashMap
використовується як кеш - смертельно. Записи можна видалити, як тільки вони створені. Це, мабуть, не відбудеться під час тестування, але цілком може бути під час використання. Зверніть увагу, NetBeans може бути доведений до ефективної стовідсоткової зупинки процесором цим.
WeakHashMap
навіть якщо ви правильні, що це поганий вибір;)
[EDIT2] Я знайшов ще один хороший приклад WeakReference
. Обробка растрових зображень Off Нитка UI сторінці в Відображення растрових зображень Ефективне навчальний посібник, демонструє одне використання 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 - це не що інше, як простий клас віджетів, який показує підказку над поданням на якір. Я зробив знімок екрана.
Клас дійсно простий (близько 200 рядків) і гідний для ознайомлення. У цьому класі WeakReference
клас використовується для посилання на вигляд якоря, що має ідеальний сенс, оскільки це дає можливість виду якоря збирати сміття навіть тоді, коли екземпляр підказки живе довше, ніж його вид прив’язки.
Щасливого кодування! :)
Дозвольте поділитися одним робочим прикладом WeakReference
класу. Це невеликий фрагмент коду з віджетом Framework Framework, який називається 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
, тому що посилається об’єкт подання переробляється в адаптерах, а не збирається сміттям.
Деякі з інших відповідей здаються неповними або занадто довгими. Ось загальна відповідь.
Ви можете виконати наступні дії:
WeakReference
змінну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);
}
}
MyClass
було A і AnotherClass
був Б.WeakReference
є те, щоб інший клас реалізував інтерфейс. Це робиться за схемою слухача / спостерігача .// allow MyClass to get a weak reference to this class void someMethod() { mMyClass = new MyClass(); mMyClass.someMethod(this); }
??
weakreference
об’єкт у doSomething
функції, щоб не бути null
перед викликом get
функції.
"Канонізоване" зіставлення - це те, коли ви зберігаєте один екземпляр розглянутого об'єкта в пам'яті, а всі інші шукають цей конкретний екземпляр за допомогою покажчиків або механізму дещо. Тут можуть допомогти посилання на слабкі місця. Коротка відповідь полягає в тому, що об'єкти 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