¿Cómo usar WeakReference en el desarrollo de Java y Android?

He sido desarrollador de Java por 2 años.

Pero nunca he escrito una WeakReference en mi código. ¿Cómo utilizar WeakReference para hacer que mi aplicación sea más eficiente, especialmente la aplicación Android?

Usar WeakReference en Android no es diferente de usar uno en Java simple. Aquí hay una gran guía que brinda una explicación detallada: Comprender las referencias débiles .

Debería pensar en usar uno cada vez que necesite una referencia a un objeto, pero no quiere esa referencia para proteger el objeto del recolector de basura. Un ejemplo clásico es un caché que desea recolectar como basura cuando el uso de la memoria es demasiado alto (a menudo implementado con WeakHashMap ).

Asegúrese de revisar SoftReference y PhantomReference también.

EDITAR: Tom ha planteado algunas preocupaciones sobre la implementación de un caché con WeakHashMap . Aquí hay un artículo que presenta los problemas: ¡ WeakHashMap no es un caché!

Tom tiene razón en que ha habido quejas sobre el bajo rendimiento de Netbeans debido al WeakHashMap caché de WeakHashMap .

Todavía creo que sería una buena experiencia de aprendizaje implementar un caché con WeakHashMap y luego compararlo con tu propio caché rodado manualmente implementado con SoftReference . En el mundo real, probablemente no use ninguna de estas soluciones, ya que tiene más sentido usar una biblioteca de terceros como Apache JCS .

[EDIT2] Encontré otro buen ejemplo de WeakReference . Procesamiento de WeakReference de WeakReference Aparece la página de subprocesos de la interfaz de usuario en la guía de capacitación de WeakReference de WeakReference de bits de manera eficiente , que muestra un uso de WeakReference en AsyncTask.

 class BitmapWorkerTask extends AsyncTask { private final WeakReference imageViewReference; private int data = 0; public BitmapWorkerTask(ImageView imageView) { // Use a WeakReference to ensure the ImageView can be garbage collected imageViewReference = new WeakReference(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,

La WeakReference a ImageView garantiza que AsyncTask no impida que ImageView y todo lo que haga referencia sea recolectado como basura . No hay garantía de que ImageView todavía esté disponible cuando la tarea finalice, por lo que también debe verificar la referencia en onPostExecute (). Es posible que ImageView ya no exista, por ejemplo, si el usuario se aleja de la actividad o si se produce un cambio en la configuración antes de que la tarea finalice.

Feliz encoding!


[EDITAR] Encontré un muy buen ejemplo de WeakReference de facebook-android-sdk . La clase ToolTipPopup no es más que una simple clase de widget que muestra información sobre herramientas sobre la vista ancla. Capturé una captura de pantalla.

deliciosa captura de pantalla

La clase es realmente simple (alrededor de 200 líneas) y digna de ser vista. En esa clase, la clase WeakReference se usa para mantener la referencia a la vista de anclaje, lo cual tiene perfecto sentido, ya que hace posible que la vista de anclaje sea basura, incluso cuando una instancia de información sobre herramientas dura más que su vista de anclaje.

Feliz encoding! 🙂


Permítanme compartir un ejemplo de WeakReference clase WeakReference . Es un pequeño fragmento de código del widget de Android framework llamado AutoCompleteTextView .

En resumen, la clase WeakReference se usa para mantener el objeto View para evitar la pérdida de memoria en este ejemplo.

Copiaré y pegaré la clase PopupDataSetObserver, que es una clase anidada de AutoCompleteTextView . Es realmente simple y los comentarios explican bien la clase. Feliz encoding! 🙂

  /** * Static inner listener that keeps a WeakReference to the actual AutoCompleteTextView. * 

* 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 mViewReference; private PopupDataSetObserver(AutoCompleteTextView view) { mViewReference = new WeakReference(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()); } }; }

Y el PopupDataSetObserver se usa para configurar el adaptador.

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

Una última cosa. También quería saber el ejemplo de trabajo de WeakReference en la aplicación de Android, y pude encontrar algunas muestras en sus aplicaciones de muestra oficiales. Pero realmente no podía entender el uso de algunos de ellos. Por ejemplo, las aplicaciones ThreadSample y DisplayingBitmaps usan WeakReference en su código, pero después de ejecutar varias pruebas, descubrí que el método get () nunca devuelve null , porque el objeto de vista referenciado se recicla en adaptadores, en lugar de recoger la basura.

Algunas de las otras respuestas parecen incompletas o demasiado largas. Aquí hay una respuesta general.

Cómo usar WeakReference en Java y Android

Puedes hacer los siguientes pasos:

  1. Crear una variable WeakReference
  2. Establecer la referencia débil
  3. Use la referencia débil

Código

MyClass tiene una referencia débil a AnotherClass .

 public class MyClass { // 1. Create a WeakReference variable private WeakReference 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 tiene una fuerte referencia 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.someMethod(this); } } 

Notas

  • La razón por la que necesita una referencia débil es para que el recolector de basura pueda deshacerse de los objetos cuando ya no sean necesarios. Si dos objetos retienen una fuerte referencia el uno al otro, entonces no pueden ser recolectados como basura. Esta es una pérdida de memoria.
  • Si dos objetos necesitan referenciarse, el objeto A (generalmente el objeto de vida más corta) debería tener una referencia débil al objeto B (generalmente el objeto más longevo), mientras que B tiene una fuerte referencia a A. En el ejemplo anterior, MyClass era A y AnotherClass fue B.
  • Una alternativa al uso de WeakReference es hacer que otra clase implemente una interfaz. Esto se hace en el patrón Listener / Observer .

Ejemplo práctico

  • Clase AsyncTask interna estática

Un mapeo “canonicalizado” es donde usted guarda una instancia del objeto en cuestión en la memoria y todos los demás buscan esa instancia particular a través de punteros o algún mecanismo. Aquí es donde las referencias de weaks pueden ayudar. La respuesta corta es que los objetos WeakReference se pueden usar para crear punteros a los objetos en su sistema y al mismo tiempo permitir que esos objetos sean recuperados por el recolector de basura una vez que salgan del scope. Por ejemplo, si tuviera un código como este:

 class Registry { private Set registeredObjects = new HashSet(); public void register(Object object) { registeredObjects.add( object ); } } 

Cualquier objeto que registre nunca será reclamado por el GC porque hay una referencia almacenada en el conjunto de objetos registeredObjects . Por otro lado, si hago esto:

 class Registry { private Set registeredObjects = new HashSet(); public void register(Object object) { registeredObjects.add( new WeakReference(object) ); } } 

Luego, cuando el GC quiera reclamar los objetos en el Conjunto, podrá hacerlo. Puede utilizar esta técnica para el almacenamiento en caché, la catalogación, etc. Consulte a continuación las referencias a debates mucho más detallados sobre GC y almacenamiento en caché.

Ref .: Recolector de basura y WeakReference