Wie verwende ich WeakReference in der Java- und Android-Entwicklung?

166

Ich bin seit 2 Jahren ein Java-Entwickler.

Aber ich habe noch nie eine WeakReference in meinen Code geschrieben. Wie verwende ich WeakReference, um meine Anwendung effizienter zu gestalten, insbesondere die Android-Anwendung?

Chris
quelle
Es könnte einen Unterschied
Pacerier

Antworten:

229

Die Verwendung von a WeakReferencein 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 , SoftReferenceund PhantomReferenceauß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 WeakHashMapCaching gegeben hat.

Ich denke immer noch, dass es eine gute Lernerfahrung wäre, einen Cache mit zu implementieren WeakHashMapund 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 .

dbyrne
quelle
15
Nein! Nein! Nein! WeakHashMapDie 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.
Tom Hawtin - Tackline
3
@ Tom Ich habe meine Antwort aktualisiert. Um fair zu sein, war ich technisch korrekt, dass Caches oft mit implementiert werden, WeakHashMapauch wenn Sie richtig sind, dass es eine schlechte Wahl ist;)
dbyrne
1
Hervorragende Antwort von dbyrne. Danke dafür. Ich sehe keinen Grund für die Chris, diese Antwort nicht zu akzeptieren.
San
@dbyrne Ich verwende Objekte in meiner Aktivität wie GridView, ImageView oder BaseAdapter. Muss ich in der onDestroy-Methode nach Abschluss der Aktivität mit diesen Objekten mithilfe von Weak / SoftReferences etwas tun? Oder bereinigt das System automatisch diesen Speicher dieses Objekts?
Beni
4
defekter Link zu java.net
Suragch
64

[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 WeakReferencevon 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.

leckerer Screenshot

Die Klasse ist sehr einfach (ca. 200 Zeilen) und sehenswert. In dieser Klasse wird die WeakReferenceKlasse 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 WeakReferenceKlasse 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 PopupDataSetObserverwird 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 WeakReferenceAndroid-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 WeakReferencein 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.

김준호
quelle
1
Vielen Dank für die tollen Beispiele - ich bin wirklich der Meinung, dass dies die akzeptierte Antwort auf die Frage sein sollte. Prost!
Ackshaey Singh
@ AckshaeySingh Danke! :)
5
16

Einige der anderen Antworten scheinen unvollständig oder zu lang zu sein. Hier ist eine allgemeine Antwort.

Verwendung von WeakReference in Java und Android

Sie können die folgenden Schritte ausführen:

  1. Erstellen Sie eine WeakReferenceVariable
  2. Stellen Sie die schwache Referenz ein
  3. Verwenden Sie die schwache Referenz

Code

MyClasshat 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
    }

}

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

Anmerkungen

  • Der Grund, warum Sie eine schwache Referenz benötigen, besteht darin, dass der Garbage Collector die Objekte entsorgen kann, wenn sie nicht mehr benötigt werden. Wenn zwei Objekte einen starken Bezug zueinander haben, können sie nicht als Müll gesammelt werden. Dies ist ein Speicherverlust.
  • Wenn zwei Objekte aufeinander verweisen müssen, sollte Objekt A (im Allgemeinen das Objekt mit der kürzeren Lebensdauer) eine schwache Referenz auf Objekt B (im Allgemeinen das Objekt mit der längeren Lebensdauer) haben, während B eine starke Referenz auf A hat. Im obigen Beispiel MyClasswar A. und AnotherClasswar B.
  • Eine Alternative zur Verwendung von a WeakReferencebesteht darin, dass eine andere Klasse eine Schnittstelle implementiert. Dies erfolgt im Listener / Observer-Muster .

Praktisches Beispiel

Suragch
quelle
verwirrende Erklärung. was ist // allow MyClass to get a weak reference to this class void someMethod() { mMyClass = new MyClass(); mMyClass.someMethod(this); }??
Likejudo
@likejudo, du hast recht. Ich habe einige der Variablen- und Methodennamen verbessert. Wie ist es jetzt?
Suragch
Sie müssen das weakreferenceObjekt selbst in der doSomethingFunktion überprüfen , damit es nicht nullvor dem Aufruf der getFunktion vorhanden ist.
Behrouz.M
7

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.

Ref: Garbage Collector und WeakReference

Akshay
quelle