Estou desenvolvendo um aplicativo Android 2.3.3 com um serviço. Eu tenho isso dentro desse serviço para se comunicar com a atividade 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());
[ ... ]
}
E aqui, final Messenger mMessenger = new Messenger(new IncomingHandler());
recebo o seguinte aviso do Lint:
This Handler class should be static or leaks might occur: IncomingHandler
O que isso significa?
Respostas:
Se a
IncomingHandler
classe não for estática, ela terá uma referência ao seuService
objeto.Handler
objetos para o mesmo encadeamento compartilham um objeto Looper comum, para o qual eles postam mensagens e leem.Como as mensagens contêm destino
Handler
, desde que haja mensagens com manipulador de destino na fila de mensagens, o manipulador não poderá ser coletado como lixo. Se manipulador não é estático, a suaService
ouActivity
não pode ser lixo coletado, mesmo depois de ser destruído.Isso pode levar a vazamentos de memória, por algum tempo, pelo menos - desde que as mensagens permaneçam na fila. Isso não é muito problemático, a menos que você poste mensagens atrasadas.
Você pode tornar
IncomingHandler
estático e ter umWeakReference
ao seu serviço:Veja este post de Romain Guy para referência adicional
fonte
get()
retornará nulo quando o objeto referenciado foi gc-ed. Nesse caso, quando o serviço estiver morto.Como outros usuários mencionaram, o aviso do Lint é devido ao possível vazamento de memória. Você pode evitar o aviso do Lint passando a
Handler.Callback
ao construirHandler
(ou seja, você não subclasseHandler
e não háHandler
classe interna não estática):Pelo que entendi, isso não evitará o possível vazamento de memória.
Message
objetos mantêm uma referência aomIncomingHandler
objeto que mantém uma referência aoHandler.Callback
objeto que mantém uma referência aoService
objeto. Enquanto houver mensagens naLooper
fila de mensagens, oService
não será o GC. No entanto, não será um problema sério, a menos que você tenha longas mensagens de atraso na fila de mensagens.fonte
Aqui está um exemplo genérico de uso de uma classe fraca de referência e manipulador estático para resolver o problema (conforme recomendado na documentação do Lint):
fonte
Myclass
deve ser declarado como empublic Handler getHandler()
vez depublic void
Dessa maneira, funcionou bem para mim, mantendo o código limpo, mantendo onde você lida com a mensagem em sua própria classe interna.
O manipulador que você deseja usar
A classe interna
fonte
Com a ajuda da resposta de @ Sogger, criei um manipulador genérico:
A interface:
Estou usando da seguinte maneira. Mas não tenho 100% de certeza se isso é à prova de vazamentos. Talvez alguém possa comentar sobre isso:
fonte
Não tenho certeza, mas você pode tentar inicializar o manipulador para nulo em onDestroy ()
fonte
Estou confuso. O exemplo que encontrei evita completamente a propriedade estática e usa o thread da interface do usuário:
O que eu mais gosto nessa solução é que não há problema em tentar misturar variáveis de classe e método.
fonte