web-dev-qa-db-fra.com

Comment utiliser WeakReference dans le développement Java et Android?

J'ai été un développeur Java pendant 2 ans.

Mais je n'ai jamais écrit de référence faible dans mon code. Comment utiliser WeakReference pour rendre mon application plus efficace, en particulier l'application Android?

156
Chris

L'utilisation de WeakReference in Android n'est pas différente de celle qui est utilisée dans un vieux Java clair. Voici un excellent guide qui donne une explication détaillée: Comprendre les références faibles .

Vous devriez penser à en utiliser un chaque fois que vous avez besoin d'une référence à un objet, mais vous ne voulez pas que cette référence protège l'objet du collecteur de mémoire. Un exemple classique est un cache que vous souhaitez récupérer à la poubelle lorsque l'utilisation de la mémoire devient trop importante (souvent implémentée avec WeakHashMap).

Veillez également à vérifier SoftReference et PhantomReference.

EDIT: Tom a exprimé des inquiétudes quant à la mise en œuvre d'un cache avec WeakHashMap. Voici un article exposant les problèmes: WeakHashMap n'est pas un cache!

Tom a raison de dire qu'il y a eu plaintes à propos de mauvaises performances Netbeans en raison de la mise en cache de WeakHashMap.

Je pense toujours que ce serait une bonne expérience d'apprentissage de mettre en œuvre un cache avec WeakHashMap puis de le comparer à votre propre cache roulé à la main implémenté avec SoftReference. Dans le monde réel, vous n'utiliseriez probablement aucune de ces solutions, car il est plus logique d'utiliser une bibliothèque tierce telle que Apache JCS .

220
dbyrne

[EDIT2] J'ai trouvé un autre bon exemple de WeakReference. Traitement des images bitmap hors du fil de l'interface utilisateur page dans Affichage efficace des images bitmap guide de formation, montre une utilisation de WeakReference en 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);
            }
        }
    }
}

Ça dit,

Le WeakReference à ImageView garantit que AsyncTask n'empêche pas ImageView et tout ce qui y est référé d'être récupérés . Il n’est pas garanti que ImageView soit toujours présent à la fin de la tâche. Vous devez donc également vérifier la référence dans onPostExecute (). ImageView peut ne plus exister si, par exemple, l'utilisateur s'éloigne de l'activité ou si un changement de configuration se produit avant la fin de la tâche.

Bon codage!


[EDIT] J'ai trouvé un très bon exemple de WeakReference de facebook-Android-sdk . ToolTipPopup La classe n'est rien d'autre qu'une classe de widgets simple qui affiche une info-bulle au-dessus de la vue d'ancrage. J'ai capturé une capture d'écran.

scrumptious screenshot

La classe est vraiment simple (environ 200 lignes) et mérite d'être regardée. Dans cette classe, la classe WeakReference est utilisée pour conserver la référence à la vue d'ancrage, ce qui est parfaitement logique, car elle permet de ramasser la vue d'ancrage, même lorsqu'une occurrence d'info-bulle a une durée de vie supérieure à celle de la vue d'ancrage.

Bon codage! :)


Permettez-moi de partager un exemple de travail de WeakReference class. C'est un petit extrait de code de Android widget de cadre appelé AutoCompleteTextView .

En bref, la classe WeakReference est utilisée pour tenir View objet à éviter fuite de mémoire dans cet exemple.

Je vais simplement copier-coller la classe PopupDataSetObserver, qui est une classe imbriquée de AutoCompleteTextView. C'est très simple et les commentaires expliquent bien la classe. Bon codage! :)

    /**
     * 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());
        }
    };
}

Et le PopupDataSetObserver est utilisé dans la configuration de l'adaptateur.

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

Une dernière chose. Je souhaitais également connaître l'exemple de travail de WeakReference dans l'application Android, et je pourrais trouver quelques exemples dans ses exemples d'applications officiels. Mais je ne comprenais vraiment pas l'utilisation qu'ils en faisaient. Par exemple, les applications ThreadSample et DisplayingBitmaps utilisent WeakReference dans leur code, mais après avoir exécuté plusieurs tests, j'ai découvert que la méthode get () ne renvoie jamais null, car l'objet de vue référencé est recyclé dans les adaptateurs, plutôt que dans les déchets collectés.

61
김준호

Certaines des autres réponses semblent incomplètes ou trop longues. Voici une réponse générale:

Comment utiliser WeakReference dans Java et Android

Vous pouvez effectuer les étapes suivantes:

  1. Créer une variable WeakReference
  2. Définir la référence faible
  3. Utilisez la référence faible

Code

MyClass a une faible référence à 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 a une forte référence à 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);
    }
}

Remarques

  • Vous avez besoin d'une référence faible pour que le ramasse-miettes puisse disposer des objets dès qu'ils ne sont plus nécessaires. Si deux objets conservent une forte référence l'un à l'autre, ils ne peuvent pas être récupérés. C'est une fuite de mémoire.
  • Si deux objets doivent se référencer, l’objet A (généralement l’objet à durée de vie la plus courte) doit avoir une faible référence à l’objet B (généralement l’objet à la vie la plus longue), alors que B a une forte référence à A. Dans l’exemple ci-dessus, MyClass était A et AnotherClass était B.
  • Une alternative à l'utilisation de WeakReference consiste à faire en sorte qu'une autre classe implémente une interface. Ceci est fait dans le Listener/Observer Pattern .

Exemple pratique

14
Suragch

Un mappage "canonisé" consiste à garder en mémoire une instance de l'objet en question et à permettre à toutes les autres de rechercher cette instance particulière via des pointeurs ou un mécanisme similaire. C'est là que les références faibles peuvent aider. La réponse courte est que les objets WeakReference peuvent être utilisés pour créer des pointeurs sur des objets de votre système tout en permettant à ces objets d'être récupérés par collecteur de déchets une fois qu'ils passent hors de la portée. Par exemple, si j'avais un code comme celui-ci:

class Registry {
     private Set registeredObjects = new HashSet();

     public void register(Object object) {
         registeredObjects.add( object );
     }
 }

Aucun objet que j'enregistre ne sera jamais récupéré par le GC car il y a une référence à celui-ci stockée dans l'ensemble de registeredObjects. Par contre si je fais ça:

class Registry {
     private Set registeredObjects = new HashSet();

     public void register(Object object) {
         registeredObjects.add( new WeakReference(object) );
     }
 }

Ensuite, lorsque le GC voudra récupérer les objets du jeu, il pourra le faire. Vous pouvez utiliser cette technique pour la mise en cache, le catalogage, etc. Voir ci-dessous des références à des discussions beaucoup plus approfondies sur la CPG et la mise en cache.

Réf: ramasse-miettes et référence faible

7
Akshay