Tworzę aplikację na Androida 2.3.3 z usługą. Mam to wewnątrz tej usługi, aby komunikować się z główną działalnością:
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());
[ ... ]
}
I tutaj final Messenger mMessenger = new Messenger(new IncomingHandler());
pojawia się następujące ostrzeżenie Lint:
This Handler class should be static or leaks might occur: IncomingHandler
Co to znaczy?
Odpowiedzi:
Jeśli
IncomingHandler
klasa nie jest statyczna, będzie miała odniesienie do twojegoService
obiektu.Handler
wszystkie obiekty tego samego wątku współużytkują wspólny obiekt Looper, do którego wysyłają wiadomości i czytają.Ponieważ wiadomości zawierają cel
Handler
, dopóki w kolejce komunikatów znajdują się komunikaty z funkcją obsługi, nie można wyrzucać pamięci. Jeżeli przewodnik nie jest statyczna, swojeService
lubActivity
nie mogą być zbierane śmieci, nawet po zniszczeniu.Może to prowadzić do wycieków pamięci, przynajmniej przez jakiś czas - o ile wiadomości pozostają w kolejce. Nie stanowi to większego problemu, chyba że opublikujesz wiadomości z dużym opóźnieniem.
Możesz zrobić
IncomingHandler
statyczne i miećWeakReference
do swojej usługi:Zobacz ten post Romain Guy w celu uzyskania dalszych odniesień
źródło
get()
zwróci null, gdy obiekt odniesienia był gc-ed. W takim przypadku, gdy usługa nie działa.Jak wspomnieli inni, ostrzeżenie Lint jest spowodowane potencjalnym wyciekiem pamięci. Możesz uniknąć ostrzeżenia Lint, przekazując a
Handler.Callback
podczas konstruowaniaHandler
(tzn. Nie podklasujeszHandler
i nie maHandler
niestatycznej klasy wewnętrznej):Jak rozumiem, nie pozwoli to uniknąć potencjalnego wycieku pamięci.
Message
obiekty zawierają odniesienie domIncomingHandler
obiektu, który zawiera odniesienie doHandler.Callback
obiektu, który zawiera odniesienie doService
obiektu. Dopóki wLooper
kolejce komunikatów znajdują się komunikaty,Service
nie będzie to GC. Nie będzie to jednak poważny problem, chyba że w kolejce wiadomości znajdują się długie wiadomości opóźniające.źródło
Oto ogólny przykład użycia słabej klasy referencyjnej i statycznej klasy procedury obsługi do rozwiązania problemu (zgodnie z zaleceniami w dokumentacji Lint):
źródło
Myclass
powinna być uznana jakopublic Handler getHandler()
zamiastpublic void
Ten sposób działał dla mnie dobrze, utrzymuje kod w czystości, utrzymując miejsce, w którym obsługujesz komunikat w jego własnej klasie wewnętrznej.
Przewodnik, którego chcesz użyć
Klasa wewnętrzna
źródło
Za pomocą odpowiedzi @ Sogger stworzyłem ogólny program obsługi:
Interfejs:
Używam tego w następujący sposób. Ale nie jestem w 100% pewien, czy to jest szczelne. Może ktoś mógłby to skomentować:
źródło
Nie jestem pewien, ale możesz spróbować zainicjalizować moduł obsługi, aby null w onDestroy ()
źródło
Jestem zmieszany. Przykład, który znalazłem, całkowicie unika właściwości statycznej i wykorzystuje wątek interfejsu użytkownika:
W tym rozwiązaniu podoba mi się to, że nie ma problemu z mieszaniem zmiennych klas i metod.
źródło