¿Cómo / cuándo se recoge una basura del Manejador?

Dentro de una clase de la mina tengo el código siguiente:

mHandler = createHandler(); private Handler createHandler() { return new Handler() { public void handleMessage (Message msg) { update(); if (!paused) { sendEmptyMessageDelayed(0, 300); } } }; } 

La documentación dice:

http://developer.android.com/reference/android/os/Handler.html

Cada instancia de Handler está asociada con un solo subproceso y la cola de mensajes de dicho subproceso

Así que si he entendido correctamente el manejador no es recolección de basura siempre y cuando el hilo de la aplicación está en ejecución, ¿es correcto?

En mi ejemplo específico, ya que el manejador es una clase interna anónima, tiene una referencia implícita al Objeto incluido ya toda la jerarquía de objetos que apunta. Esto me parece una receta para fugas de memoria.

Por cierto, puedo hacer que el Handler deje de enviar mensajes (es por eso que tengo el if (!paused) ) pero esto no hará que sea GCed, ¿verdad?

¿Así que hay una manera de eliminar el Handler de la cola de mensajes y conseguir que se GCed?

En mi ejemplo específico, ya que el manejador es una clase interna anónima, tiene una referencia implícita al Objeto incluido ya toda la jerarquía de objetos que apunta.

Podría reducir el impacto de la fuga potencial a casi nada utilizando una clase anidada static lugar de una clase interna anónima.

Un examen de la fuente Handler revela más detalles.

He aquí un código de depuración del constructor Handler () que fue agregado por Romain Guy:

 if (FIND_POTENTIAL_LEAKS) { final Class<? extends Handler> klass = getClass(); if ((klass.isAnonymousClass() || klass.isMemberClass() || klass.isLocalClass()) && (klass.getModifiers() & Modifier.STATIC) == 0) { Log.w(TAG, "The following Handler class should be static or leaks might occur: " + klass.getCanonicalName()); } } 

La advertencia es clara: no declare su subclase Handler como una clase interna.

El buscador del Handler se obtiene de una instancia ThreadLocal estática:

 mLooper = Looper.myLooper(); /** * Return the Looper object associated with the current thread. Returns * null if the calling thread is not associated with a Looper. */ public static final Looper myLooper() { return (Looper)sThreadLocal.get(); } 

Anatomía de la fuga:

El hilo principal de la aplicación conserva el Looper y su MessageQueue, los mensajes en la cola conservan un vínculo a su controlador de destino y el Handler (a menos que sea una clase anidada estática con un WeakReference a su actividad) conservará su actividad y su puntos de vista.

En su lugar, podría intentar conectar esta fuga limpiando sus mensajes:

 handler.removeMessages(what); 

Pero esto es más fácil decirlo que hacerlo.

También vea Sobre fugas de memoria en Java y en Android

No, dejar de enviar mensajes no hace que la GC funcione. Como señala el doc, limita al hilo que lo crea. Si el subproceso está en ejecución, el controlador no será reciclado por GC.

¿Por qué cree que esto podría causar fugas de memoria? ¿Qué quieres decir con "referencia implícita al Objeto que lo envuelve"?

FlipAndroid es un fan de Google para Android, Todo sobre Android Phones, Android Wear, Android Dev y Aplicaciones para Android Aplicaciones.