He sido desarrollador de Java durante 2 años.
Pero nunca he escrito una WeakReference en mi código. ¿Cómo usar WeakReference para hacer que mi aplicación sea más eficiente, especialmente la aplicación de Android?
He sido desarrollador de Java durante 2 años.
Pero nunca he escrito una WeakReference en mi código. ¿Cómo usar WeakReference para hacer que mi aplicación sea más eficiente, especialmente la aplicación de Android?
Respuestas:
Usar un WeakReference
en Android no es diferente de usar uno en Java antiguo. 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 desea que esa referencia proteja el objeto del recolector de basura. Un ejemplo clásico es un caché en el que desea recolectar basura cuando el uso de memoria es demasiado alto (a menudo implementado conWeakHashMap
).
Asegúrese de revisar SoftReference
yPhantomReference
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 aWeakHashMap
almacenamiento caché.
Todavía creo que sería una buena experiencia de aprendizaje implementar un caché WeakHashMap
y luego compararlo con su propio caché enrollado a mano implementado SoftReference
. En el mundo real, probablemente no usaría ninguna de estas soluciones, ya que tiene más sentido usar una biblioteca de terceros como Apache JCS .
WeakHashMap
usado como caché es fatal. Las entradas se pueden eliminar tan pronto como se crean. Esto probablemente no sucederá cuando esté realizando la prueba, pero puede ocurrir cuando esté en uso. Es de destacar que NetBeans puede llegar a una parada efectiva del 100% de la CPU con esto.
WeakHashMap
incluso si usted es correcto, es una mala elección;)
[EDIT2] Encontré otro buen ejemplo de WeakReference
. Procesar mapas de bits fuera de la página de subprocesos de la interfaz de usuario en la guía de capacitación Visualización eficiente de WeakReference
mapas de bits , muestra un uso de 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,
La WeakReference a ImageView garantiza que AsyncTask no impida que se recoja basura ImageView y cualquier cosa a la que haga referencia . No hay garantía de que ImageView siga existiendo cuando finalice la tarea, por lo que también debe verificar la referencia en onPostExecute (). Es posible que ImageView ya no exista, si, por ejemplo, el usuario se aleja de la actividad o si se produce un cambio de configuración antes de que finalice la tarea.
¡Feliz codificación!
[EDIT] me encontré con un muy buen ejemplo de WeakReference
desde facebook-android-sdk . La clase ToolTipPopup no es más que una clase de widget simple que muestra información sobre herramientas sobre la vista de anclaje. Capturé una captura de pantalla.
La clase es realmente simple (alrededor de 200 líneas) y digna de ver. En esa clase,WeakReference
clase se usa para mantener referencia a la vista de anclaje, lo que tiene mucho sentido, ya que hace posible que la vista de anclaje se recolecte basura incluso cuando una instancia de información sobre herramientas dura más que su vista de anclaje.
¡Feliz codificación! :)
Permítanme compartir un ejemplo WeakReference
práctico de clase. Es un pequeño fragmento de código del widget de marco de Android llamado AutoCompleteTextView
.
En resumen, la WeakReference
clase se usa para contener View
objetos para evitar pérdidas 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 codificación! :)
/**
* 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());
}
};
}
Y PopupDataSetObserver
se usa para configurar el adaptador.
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);
}
Una última cosa. También quería saber ejemplos de trabajo WeakReference
en aplicaciones 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, ThreadSample y DisplayingBitmaps aplicaciones utilizan WeakReference
en su código, pero después de correr varias pruebas, he encontrado que el método get () no vuelve nunca null
, porque la vista referenciada objeto se recicla en los adaptadores, en lugar de basura recogida.
Algunas de las otras respuestas parecen incompletas o demasiado largas. Aquí hay una respuesta general.
Puedes hacer los siguientes pasos:
WeakReference
variableMyClass
tiene una referencia débil 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
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.setWeakReference(this);
}
}
MyClass
era A y AnotherClass
fue B.WeakReference
es hacer que otra clase implemente una interfaz. Esto se hace en el patrón de escucha / observador .// allow MyClass to get a weak reference to this class void someMethod() { mMyClass = new MyClass(); mMyClass.someMethod(this); }
??
weakreference
objeto en sí mismo en la doSomething
función para que no esté null
antes de llamar a la get
función.
Un mapeo "canonicalizado" es donde mantiene una instancia del objeto en cuestión en la memoria y todas las demás buscan esa instancia en particular a través de punteros o algún mecanismo. Aquí es donde las referencias de los débiles pueden ayudar. La respuesta corta es que los objetos WeakReference se pueden usar para crear punteros a objetos en su sistema y al mismo tiempo permitir que esos objetos sean reclamados por el recolector de basura una vez que pasan del alcance. 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 a él almacenado en el conjunto de 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é.