Sono stato uno sviluppatore Java per 2 anni.
Ma non ho mai scritto un riferimento debole nel mio codice. Come utilizzare WeakReference per rendere la mia applicazione più efficiente, in particolare l'applicazione Android?
Sono stato uno sviluppatore Java per 2 anni.
Ma non ho mai scritto un riferimento debole nel mio codice. Come utilizzare WeakReference per rendere la mia applicazione più efficiente, in particolare l'applicazione Android?
Risposte:
L'uso di a WeakReference
in Android non è diverso dall'uso di uno in Java semplicemente vecchio. Ecco una grande guida che fornisce una spiegazione dettagliata: Comprensione dei riferimenti deboli .
Dovresti pensare di usarne uno ogni volta che hai bisogno di un riferimento a un oggetto, ma non vuoi quel riferimento per proteggere l'oggetto dal Garbage Collector. Un classico esempio è una cache che si desidera raccogliere in modo inutile quando l'utilizzo della memoria diventa troppo elevato (spesso implementato con WeakHashMap
).
Assicurati di controllare SoftReference
e PhantomReference
pure.
EDIT: Tom ha sollevato alcune preoccupazioni sull'implementazione di una cache con WeakHashMap
. Ecco un articolo che illustra i problemi: WeakHashMap non è una cache!
Tom ha ragione nel dire che ci sono state lamentele per le scarse prestazioni di Netbeans dovute alla WeakHashMap
memorizzazione nella cache.
Continuo a pensare che sarebbe una buona esperienza di apprendimento implementare una cache WeakHashMap
e poi confrontarla con la propria cache implementata manualmente SoftReference
. Nel mondo reale, probabilmente non useresti nessuna di queste soluzioni, dal momento che ha più senso usare una libreria di terze parti come Apache JCS .
WeakHashMap
usato come cache è fatale. Le voci possono essere rimosse non appena vengono create. Questo probabilmente non accadrà durante il test, ma potrebbe anche essere in uso. Da notare che NetBeans può essere arrestato al 100% dalla CPU.
WeakHashMap
anche se hai ragione sul fatto che si tratta di una scelta sbagliata;)
[EDIT2] Ho trovato un altro buon esempio di WeakReference
. Elaborazione di bitmap dalla pagina Discussione dell'interfaccia utente in Visualizzazione di bitmap Guida all'addestramento efficiente , mostra un utilizzo di WeakReference
in 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);
}
}
}
}
Dice,
Il riferimento debole a ImageView assicura che AsyncTask non impedisca a ImageView e tutto ciò a cui fa riferimento di essere raccolto . Non c'è garanzia che ImageView sia ancora in giro al termine dell'attività, quindi è necessario controllare anche il riferimento in onPostExecute (). ImageView potrebbe non esistere più, ad esempio se l'utente si allontana dall'attività o se si verifica una modifica della configurazione prima del completamento dell'attività.
Buona programmazione!
[EDIT] Ho trovato un ottimo esempio di WeakReference
da facebook-android-sdk . ToolTipPopup classe non è altro che una semplice classe di widget che mostra una descrizione comandi sopra la vista di ancoraggio. Ho catturato uno screenshot.
La classe è davvero semplice (circa 200 righe) e degna di essere vista. In quella classe, la WeakReference
classe viene utilizzata per contenere il riferimento alla vista di ancoraggio, il che ha perfettamente senso, perché rende possibile che la vista di ancoraggio venga raccolta in modo errato anche quando un'istanza di tooltip vive più a lungo della sua vista di ancoraggio.
Buona programmazione! :)
Vorrei condividere un esempio funzionante di WeakReference
classe. È un piccolo frammento di codice dal widget del framework Android chiamato AutoCompleteTextView
.
In breve, la WeakReference
classe viene utilizzata per contenere l' View
oggetto per impedire la perdita di memoria in questo esempio.
Copierò e incollerò semplicemente la classe PopupDataSetObserver, che è una classe nidificata di AutoCompleteTextView
. È davvero semplice e i commenti spiegano bene la lezione. Buona programmazione! :)
/**
* 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());
}
};
}
E PopupDataSetObserver
viene utilizzato nell'adattatore di impostazione.
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);
}
Un'ultima cosa. Volevo anche sapere un esempio funzionante WeakReference
dell'applicazione Android, e ho potuto trovare alcuni esempi nelle sue applicazioni campione ufficiali. Ma non riuscivo davvero a capire alcuni dei loro usi. Ad esempio, ThreadSample e DisplayingBitmaps applicazioni utilizzano WeakReference
nel codice, ma dopo aver eseguito vari test, ho trovato che il metodo get () non ritorna null
, perché fa riferimento sottofinestra viene riciclato in adattatori, piuttosto che garbage collection.
Alcune delle altre risposte sembrano incomplete o eccessivamente lunghe. Ecco una risposta generale.
Puoi fare i seguenti passi:
WeakReference
variabileMyClass
ha un riferimento debole a 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
ha un forte riferimento a 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
era A eAnotherClass
era B.WeakReference
è avere un'altra classe implementare un'interfaccia. Questo viene fatto nel modello di ascolto / osservatore .// allow MyClass to get a weak reference to this class void someMethod() { mMyClass = new MyClass(); mMyClass.someMethod(this); }
??
weakreference
oggetto stesso nella doSomething
funzione per non essere null
prima di chiamare la get
funzione.
Una mappatura "canonicalizzata" è quella in cui si tiene in memoria un'istanza dell'oggetto in questione e tutte le altre cercano quella particolare istanza tramite puntatori o meccanismo simile. Questo è dove i riferimenti deboli possono aiutare. La risposta breve è che gli oggetti WeakReference possono essere utilizzati per creare puntatori agli oggetti nel sistema pur consentendo a tali oggetti di essere recuperati dal Garbage Collector dopo che sono usciti dall'ambito. Ad esempio se avessi un codice come questo:
class Registry {
private Set registeredObjects = new HashSet();
public void register(Object object) {
registeredObjects.add( object );
}
}
Qualsiasi oggetto che registro non verrà mai reclamato dal GC perché è presente un riferimento memorizzato nel set di registeredObjects
. D'altra parte se lo faccio:
class Registry {
private Set registeredObjects = new HashSet();
public void register(Object object) {
registeredObjects.add( new WeakReference(object) );
}
}
Quindi, quando il GC vuole recuperare gli oggetti nel Set, sarà in grado di farlo. È possibile utilizzare questa tecnica per la memorizzazione nella cache, la catalogazione, ecc. Vedere di seguito i riferimenti a discussioni molto più approfondite su GC e cache.