Estoy desarrollando una aplicación Android 2.3.3 con un servicio. Tengo esto dentro de ese servicio para comunicarme con la actividad principal:
public class UDPListenerService extends Service
{
private static final String TAG = "UDPListenerService";
//private ThreadGroup myThreads = new ThreadGroup("UDPListenerServiceWorker");
private UDPListenerThread myThread;
/**
* Handler to communicate from WorkerThread to service.
*/
private Handler mServiceHandler;
// Used to receive messages from the Activity
final Messenger inMessenger = new Messenger(new IncomingHandler());
// Use to send message to the Activity
private Messenger outMessenger;
class IncomingHandler extends Handler
{
@Override
public void handleMessage(Message msg)
{
}
}
/**
* Target we publish for clients to send messages to Incoming Handler.
*/
final Messenger mMessenger = new Messenger(new IncomingHandler());
[ ... ]
}
Y aquí, final Messenger mMessenger = new Messenger(new IncomingHandler());
recibo la siguiente advertencia de pelusa:
This Handler class should be static or leaks might occur: IncomingHandler
Qué significa eso?
Respuestas:
Si la
IncomingHandler
clase no es estática, tendrá una referencia a suService
objeto.Handler
Todos los objetos para el mismo hilo comparten un objeto Looper común, en el que publican mensajes y leen.Como los mensajes contienen destino
Handler
, siempre que haya mensajes con un controlador de destino en la cola de mensajes, el controlador no puede ser recolectado como basura. Si manejador no es estática, elService
oActivity
no puede ser basura recogida, incluso después de ser destruido.Esto puede provocar pérdidas de memoria, al menos durante un tiempo, siempre y cuando los mensajes permanezcan en la cola. Esto no es un gran problema a menos que publique mensajes muy retrasados.
Puede hacer
IncomingHandler
estática y tener unWeakReference
a su servicio:Vea esta publicación de Romain Guy para más referencias
fuente
get()
devolverá nulo cuando el objeto al que se hizo referencia fue gc-ed. En este caso, cuando el servicio está muerto.Como otros han mencionado, la advertencia Lint se debe a la posible pérdida de memoria. Puede evitar la advertencia de pelusa pasando un
Handler.Callback
al construirHandler
(es decir, no subclaseHandler
y no hayHandler
una clase interna no estática):Según tengo entendido, esto no evitará la pérdida potencial de memoria.
Message
los objetos contienen una referencia almIncomingHandler
objeto que contiene una referencia alHandler.Callback
objeto que contiene una referencia alService
objeto. Mientras haya mensajes en laLooper
cola de mensajes,Service
no será GC. Sin embargo, no será un problema grave a menos que tenga mensajes de gran retraso en la cola de mensajes.fuente
Aquí hay un ejemplo genérico de uso de una referencia débil y una clase de controlador estático para resolver el problema (como se recomienda en la documentación de Lint):
fuente
Myclass
debe declararse como enpublic Handler getHandler()
lugar depublic void
De esta manera funcionó bien para mí, mantiene el código limpio al mantener donde maneja el mensaje en su propia clase interna.
El manejador que deseas usar
La clase interna
fuente
Con la ayuda de la respuesta de @ Sogger, creé un controlador genérico:
La interfaz:
Lo estoy usando de la siguiente manera. Pero no estoy 100% seguro de si esto es a prueba de fugas. Tal vez alguien podría comentar sobre esto:
fuente
No estoy seguro, pero puedes probar el controlador de inicialización para anular en onDestroy ()
fuente
Estoy confundido. El ejemplo que encontré evita la propiedad estática por completo y usa el hilo de la interfaz de usuario:
Lo que me gusta de esta solución es que no hay problema al intentar mezclar variables de clase y método.
fuente