Antworten:
Die Verwendung von a WeakReference
in Android unterscheidet sich nicht von der Verwendung in einfachem altem Java. Hier ist eine großartige Anleitung, die eine detaillierte Erklärung gibt: Schwache Referenzen verstehen .
Sie sollten darüber nachdenken, eine zu verwenden, wenn Sie einen Verweis auf ein Objekt benötigen, aber Sie möchten nicht, dass dieser Verweis das Objekt vor dem Garbage Collector schützt. Ein klassisches Beispiel ist ein Cache, in dem Müll gesammelt werden soll, wenn die Speichernutzung zu hoch wird (häufig implementiert mit WeakHashMap
).
Achten Sie darauf , zu prüfen , SoftReference
und PhantomReference
außerdem.
EDIT: Tom hat einige Bedenken hinsichtlich der Implementierung eines Caches mit geäußert WeakHashMap
. Hier ist ein Artikel, der die Probleme beschreibt: WeakHashMap ist kein Cache!
Tom hat Recht, dass es Beschwerden über schlechte Netbeans-Leistung aufgrund von WeakHashMap
Caching gegeben hat.
Ich denke immer noch, dass es eine gute Lernerfahrung wäre, einen Cache mit zu implementieren WeakHashMap
und ihn dann mit Ihrem eigenen handgerollten Cache zu vergleichen, mit dem implementiert wurde SoftReference
. In der realen Welt würden Sie wahrscheinlich keine dieser Lösungen verwenden, da es sinnvoller ist, eine Bibliothek eines Drittanbieters wie Apache JCS zu verwenden .
WeakHashMap
Die Verwendung als Cache ist fatal. Einträge können entfernt werden, sobald sie erstellt wurden. Dies wird wahrscheinlich nicht passieren, wenn Sie testen, kann aber durchaus sein, wenn Sie es verwenden. Zu beachten ist, dass NetBeans auf diese Weise zu einem effektiven 100% igen CPU-Stopp gebracht werden kann.
WeakHashMap
auch wenn Sie richtig sind, dass es eine schlechte Wahl ist;)
[EDIT2] Ich habe ein weiteres gutes Beispiel dafür gefunden WeakReference
. Verarbeiten von Bitmaps Auf der Seite " UI-Thread " im Handbuch " BitmapsWeakReference
anzeigen Effizientes Training" wird eine Verwendung in AsyncTask angezeigt.
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);
}
}
}
}
Es sagt,
Die schwache Referenz auf die ImageView stellt sicher, dass die AsyncTask nicht verhindert, dass die ImageView und alles, worauf sie verweist, durch Müll gesammelt wird . Es gibt keine Garantie dafür, dass ImageView nach Abschluss der Aufgabe noch verfügbar ist. Sie müssen daher auch die Referenz in onPostExecute () überprüfen. Die ImageView ist möglicherweise nicht mehr vorhanden, wenn der Benutzer beispielsweise von der Aktivität weg navigiert oder wenn eine Konfigurationsänderung vor Abschluss der Aufgabe erfolgt.
Viel Spaß beim Codieren!
[EDIT] Ich habe ein wirklich gutes Beispiel WeakReference
von Facebook-Android-SDK gefunden . Die ToolTipPopup- Klasse ist nichts anderes als eine einfache Widget-Klasse, die den Tooltip über der Ankeransicht anzeigt. Ich habe einen Screenshot aufgenommen.
Die Klasse ist sehr einfach (ca. 200 Zeilen) und sehenswert. In dieser Klasse wird die WeakReference
Klasse verwendet, um einen Verweis auf die Ankeransicht zu speichern, was durchaus sinnvoll ist, da die Ankeransicht auch dann als Müll gesammelt werden kann, wenn eine Tooltip-Instanz länger als ihre Ankeransicht lebt.
Viel Spaß beim Codieren! :) :)
Lassen Sie mich ein Arbeitsbeispiel der WeakReference
Klasse teilen . Es ist ein kleines Code-Snippet aus dem Android Framework Widget namens AutoCompleteTextView
.
Kurz gesagt, WeakReference
Klasse wird verwendet, um ein Objekt zu halten View
, um in diesem Beispiel einen Speicherverlust zu verhindern .
Ich kopiere einfach die PopupDataSetObserver-Klasse, die eine verschachtelte Klasse von ist AutoCompleteTextView
. Es ist wirklich einfach und die Kommentare erklären die Klasse gut. Viel Spaß beim Codieren! :) :)
/**
* 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());
}
};
}
Und der PopupDataSetObserver
wird beim Einstellen des Adapters verwendet.
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);
}
Eine letzte Sache. Ich wollte auch ein funktionierendes Beispiel für eine WeakReference
Android-Anwendung kennen und konnte einige Beispiele in den offiziellen Beispielanwendungen finden. Aber ich konnte einige von ihnen wirklich nicht verstehen. Zum Beispiel verwenden ThreadSample- und DisplayingBitmaps- Anwendungen WeakReference
in ihrem Code, aber nach dem Ausführen mehrerer Tests stellte ich fest, dass die get () -Methode niemals zurückgegeben wird null
, da das referenzierte Ansichtsobjekt in Adaptern recycelt wird und nicht der gesammelte Müll.
Einige der anderen Antworten scheinen unvollständig oder zu lang zu sein. Hier ist eine allgemeine Antwort.
Sie können die folgenden Schritte ausführen:
WeakReference
VariableMyClass
hat einen schwachen Bezug zu 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
hat einen starken Bezug zu 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
war A. und AnotherClass
war B.WeakReference
besteht darin, dass eine andere Klasse eine Schnittstelle implementiert. Dies erfolgt im Listener / Observer-Muster .// allow MyClass to get a weak reference to this class void someMethod() { mMyClass = new MyClass(); mMyClass.someMethod(this); }
??
weakreference
Objekt selbst in der doSomething
Funktion überprüfen , damit es nicht null
vor dem Aufruf der get
Funktion vorhanden ist.
Bei einer "kanonisierten" Zuordnung behalten Sie eine Instanz des betreffenden Objekts im Speicher und alle anderen suchen diese bestimmte Instanz über Zeiger oder einen solchen Mechanismus. Hier können schwache Referenzen helfen. Die kurze Antwort lautet, dass WeakReference- Objekte verwendet werden können, um Zeiger auf Objekte in Ihrem System zu erstellen, während diese Objekte vom Garbage-Collector zurückgefordert werden können, sobald sie den Gültigkeitsbereich verlassen. Zum Beispiel, wenn ich Code wie diesen hätte:
class Registry {
private Set registeredObjects = new HashSet();
public void register(Object object) {
registeredObjects.add( object );
}
}
Jedes Objekt, das ich registriere, wird vom GC niemals zurückgefordert, da im Satz von ein Verweis darauf gespeichert ist registeredObjects
. Auf der anderen Seite, wenn ich das mache:
class Registry {
private Set registeredObjects = new HashSet();
public void register(Object object) {
registeredObjects.add( new WeakReference(object) );
}
}
Wenn der GC dann die Objekte im Set zurückfordern möchte, kann er dies tun. Sie können diese Technik zum Zwischenspeichern, Katalogisieren usw. verwenden. Im Folgenden finden Sie Verweise auf ausführlichere Erläuterungen zu GC und Zwischenspeichern.