Jak sprawdzić, czy usługa w tle jest uruchomiona?
Chcę aktywność Androida, która przełącza stan usługi - pozwala mi ją włączać, jeśli jest wyłączona, i wyłączać, jeśli jest włączona.
android
android-service
pszczoła
źródło
źródło
getRunningTasks()
, prawdopodobnie tak będzie.Odpowiedzi:
Niedawno miałem ten sam problem. Ponieważ moja usługa była lokalna, po prostu użyłem pola statycznego w klasie usługi do przełączania stanu, jak opisano tutaj przez hackbod
EDYCJA (dla zapisu):
Oto rozwiązanie zaproponowane przez hackbod:
źródło
onDestroy()
nie jest wywoływana. Tak więc zmiennej statycznej nie można zaktualizować w takim scenariuszu, co spowoduje niespójne zachowanie.Używam następujących czynności z działania:
I nazywam to za pomocą:
Działa to niezawodnie, ponieważ opiera się na informacjach o uruchomionych usługach dostarczanych przez system operacyjny Android za pośrednictwem ActivityManager # getRunningServices .
Wszystkie podejścia wykorzystujące zdarzenia onDestroy lub onSometing, Bindery lub zmienne statyczne nie będą działać niezawodnie, ponieważ jako programista nigdy nie wiadomo, kiedy Android decyduje się zabić proces lub które z wymienionych wywołań zwrotnych są wywoływane, czy nie. Zwróć uwagę na kolumnę „możliwą do przełknięcia” w tabeli zdarzeń cyklu życia w dokumentacji systemu Android.
źródło
getRunningServices
jest przestarzała. Ta odpowiedź wymaga aktualizacji do nowszej wersji.Rozumiem!
Państwo musi zadzwonić
startService()
do usługi mają być prawidłowo zarejestrowane i mijaniaBIND_AUTO_CREATE
nie wystarczą.A teraz klasa ServiceTools:
źródło
Małe uzupełnienie to:
Moim celem jest wiedzieć, czy usługa jest uruchomiona bez faktycznego uruchomienia, jeśli nie jest uruchomiona.
Wywołanie bindService lub zamiaru, który może zostać przechwycony przez usługę, nie jest dobrym pomysłem, ponieważ uruchomi usługę, jeśli nie jest uruchomiona.
Tak więc, jak sugerował miracle2k, najlepiej jest mieć pole statyczne w klasie usług, aby wiedzieć, czy usługa została uruchomiona, czy nie.
Aby uczynić go jeszcze czystszym, proponuję przekształcić usługę w singleton z bardzo bardzo leniwym pobieraniem: to znaczy, nie ma instancji w żadnej instancji singletonu metodami statycznymi. Statyczna metoda getInstance usługi / singletonu po prostu zwraca instancję singletonu, jeśli została utworzona. Ale tak naprawdę nie uruchamia ani nie zinstytucjonalizuje samego singletona. Usługa jest uruchamiana tylko za pomocą normalnych metod uruchamiania usługi.
Byłoby wtedy jeszcze czystsze zmodyfikowanie wzorca projektowego singletonu, aby zmienić nazwę mylącej metody getInstance na coś w rodzaju
isInstanceCreated() : boolean
metody.Kod będzie wyglądał następująco:
To rozwiązanie jest eleganckie, ale jest istotne tylko wtedy, gdy masz dostęp do klasy usługi i tylko dla klas znajduje się aplikacja / pakiet usługi. Jeśli Twoje klasy znajdują się poza aplikacją / pakietem usług, możesz przesłać zapytanie do ActivityManager z ograniczeniami podkreślonymi przez Pietera-Jana Van Robaysa.
źródło
Możesz użyć tego (jeszcze tego nie próbowałem, ale mam nadzieję, że to zadziała):
Metoda startService zwraca obiekt ComponentName, jeśli istnieje już uruchomiona usługa. Jeśli nie, zwracana jest wartość null.
Zobacz publiczne streszczenie ComponentName startService (usługa zamierzona) .
Myślę, że to nie jest jak sprawdzanie, ponieważ uruchamia usługę, więc możesz dodać
stopService(someIntent);
kod.źródło
if(startService(someIntent) != null)
to sprawdzi,IsserviceRunning
ale to również uruchomi nową usługę.źródło
Wyciąg z dokumentów Androida :
Pomyśl o tym hacku jako o „pingowaniu”
Service
. Ponieważ możemy nadawać synchronicznie, możemy nadawać i uzyskiwać wyniki synchronicznie w wątku interfejsu użytkownika.Service
Activity
Zwycięzcą w wielu aplikacjach jest oczywiście statyczne pole boolowskie w usłudze, która jest ustawiona na
true
inService.onCreate()
ifalse
in,Service.onDestroy()
ponieważ jest o wiele prostsza.źródło
Lekko zmodyfikowałem jedno z przedstawionych powyżej rozwiązań, ale przekazałem klasę zamiast ogólnej nazwy łańcucha, aby mieć pewność, że porównasz łańcuchy wychodzące z tej samej metody
class.getName()
i wtedy
źródło
Class<? extends Service>
Właściwym sposobem sprawdzenia, czy usługa jest uruchomiona, jest po prostu zapytanie. Zaimplementuj BroadcastReceiver w swojej usłudze, który reaguje na pingi z twoich działań. Zarejestruj BroadcastReceiver przy uruchomieniu usługi i wyrejestruj go, gdy usługa zostanie zniszczona. Ze swojej aktywności (lub dowolnego komponentu) wyślij lokalny zamiar transmisji do usługi, a jeśli odpowie, wiesz, że jest uruchomiony. Zwróć uwagę na subtelną różnicę między ACTION_PING i ACTION_PONG w poniższym kodzie.
źródło
Chcę tylko dodać notatkę do odpowiedzi @Snicolas. Poniższych kroków można użyć do sprawdzenia zatrzymania usługi z / bez połączenia
onDestroy()
.onDestroy()
o nazwie: Przejdź do Ustawienia -> Aplikacja -> Uruchamianie usług -> Wybierz i zatrzymaj usługę.onDestroy()
brak połączenia: Wybierz Ustawienia -> Aplikacja -> Zarządzaj aplikacjami -> Wybierz i „Wymuś zatrzymanie” aplikacji, w której działa usługa. Ponieważ jednak aplikacja zostanie zatrzymana, więc instancje usługi również zostaną zatrzymane.Na koniec chciałbym wspomnieć, że podejście wspomniane tam przy użyciu zmiennej statycznej w klasie singleton działa dla mnie.
źródło
onDestroy
nie zawsze jest wywoływany w serwisie, więc jest to bezużyteczne!Na przykład: Wystarczy uruchomić aplikację ponownie z jedną zmianą w stosunku do Eclipse. Aplikacja jest zamykana przy użyciu SIG: 9.
źródło
Przede wszystkim nie możesz próbować uzyskać dostępu do usługi za pomocą menedżera aktywności ActivityManager. (Omówiono tutaj )
Usługi mogą być uruchamiane samodzielnie, być powiązane z Działaniem lub jednym i drugim. Sposobem na sprawdzenie działania, jeśli usługa jest uruchomiona, jest utworzenie interfejsu (który rozszerza Binder), w którym deklarujesz metody zrozumiałe zarówno dla działania, jak i usługi. Możesz to zrobić, tworząc własny interfejs, w którym deklarujesz na przykład „isServiceRunning ()”. Następnie możesz powiązać działanie z usługą, uruchomić metodę isServiceRunning (), usługa sprawdzi, czy jest uruchomiona, i zwróci wartość logiczną do działania.
Możesz także użyć tej metody, aby zatrzymać Usługę lub wejść w interakcję z nią w inny sposób.
Skorzystałem z tego samouczka, aby dowiedzieć się, jak zaimplementować ten scenariusz w mojej aplikacji.
źródło
Znowu kolejna alternatywa, którą ludzie mogą znaleźć czystszą, jeśli użyją oczekujących zamiarów (na przykład z
AlarmManager
:Gdzie
CODE
jest stała, którą definiujesz prywatnie w swojej klasie, aby zidentyfikować oczekujące zamiary związane z twoją usługą.źródło
Poniżej znajduje się elegancki hack, który obejmuje wszystkie
Ifs
. Dotyczy to tylko usług lokalnych.A później:
źródło
Wersja Xamarin C #:
źródło
GetSystemService
.W podanym tutaj przypadku użycia możemy po prostu użyć
stopService()
wartości zwracanej przez metodę. Zwraca,true
jeśli istnieje określona usługa i zostanie zabita. W przeciwnym razie powrócifalse
. Możesz więc ponownie uruchomić usługę, jeśli wynik jestfalse
inny, masz pewność, że bieżąca usługa została zatrzymana. :) Byłoby lepiej, jeśli spojrzeć na to .źródło
Kolejne podejście z wykorzystaniem kotlina. Inspirowane odpowiedziami innych użytkowników
Jako rozszerzenie kotlin
Stosowanie
źródło
W kotlin możesz dodać zmienną boolowską do obiektu towarzyszącego i sprawdzić jej wartość z dowolnej klasy:
Zmień wartość, gdy usługa zostanie utworzona i zniszczona
źródło
W swojej podklasie usługi użyj statycznego boolean, aby uzyskać stan usługi, jak pokazano poniżej.
MyService.kt
MainActivity.kt
źródło
W przypadku kotlin możesz użyć poniższego kodu.
źródło
Telefon
źródło
ActivityManager.getRunningServices
jest przestarzałe, ponieważ Android OMoże istnieć kilka usług o tej samej nazwie klasy.
Właśnie stworzyłem dwie aplikacje. Nazwa pakietu pierwszej aplikacji to
com.example.mock
. Utworzyłem sub-pakiet o nazwielorem
w aplikacji i usługę o nazwieMock2Service
. Więc jego w pełni kwalifikowana nazwa tocom.example.mock.lorem.Mock2Service
.Następnie stworzyłem drugą aplikację i usługę o nazwie
Mock2Service
. Nazwa pakietu drugiej aplikacji tocom.example.mock.lorem
. Pełna nazwa usługi tocom.example.mock.lorem.Mock2Service
.Oto mój wynik logcat.
Lepszym pomysłem jest porównanie
ComponentName
przypadkach, ponieważequals()
wComponentName
porównuje obie nazwy pakietów i nazwy klas. I na urządzeniu nie mogą być zainstalowane dwie aplikacje o tej samej nazwie pakietu.Metoda equals () z
ComponentName
.ComponentName
źródło
Proszę użyć tego kodu.
źródło
Dotyczy to bardziej debugowania usługi intent, ponieważ odradzają one wątek, ale mogą również działać w przypadku zwykłych usług. Znalazłem ten wątek dzięki Binging
W moim przypadku bawiłem się debuggerem i znalazłem widok wątku. Wygląda to jak ikona punktora w MS Word. W każdym razie nie musisz być w trybie debugowania, aby z niego korzystać. Kliknij proces i kliknij ten przycisk. Wszelkie usługi zamierzone pojawią się podczas ich działania, przynajmniej na emulatorze.
źródło
Jeśli usługa należy do innego procesu lub pakietu APK, użyj rozwiązania opartego na menedżerze aktywności ActivityManager.
Jeśli masz dostęp do jego źródła, skorzystaj z rozwiązania opartego na polu statycznym. Zamiast tego używając wartości logicznej sugerowałbym użycie obiektu Date. Gdy usługa jest uruchomiona, po prostu zaktualizuj jej wartość na „teraz”, a kiedy zakończy, ustaw ją na null. Na podstawie działania możesz sprawdzić, czy jego wartość zerowa lub data jest za stara, co oznacza, że nie jest uruchomiona.
Możesz również wysłać powiadomienie o transmisji ze swojej usługi, wskazując, że działa on wraz z dalszymi informacjami, takimi jak postęp.
źródło
Wewnątrz klasy TheServiceClass zdefiniuj:
Następnie w onStartCommand (...)
Następnie zadzwoń
if(TheServiceClass.serviceRunning == true)
z dowolnej klasy.źródło
stopService
. Przynajmniej w przypadku usług Intent.onDestroy()
zostanie wezwany natychmiast, aleonHandleIntent()
nadal będzie działałproste użycie powiązania z nie twórz auto- patrz ps. i zaktualizuj ...przykład:
dlaczego nie używasz? getRunningServices ()
Uwaga: ta metoda jest przeznaczona wyłącznie do debugowania lub implementacji interfejsów użytkownika typu zarządzania usługami.
ps. Dokumentacja Androida wprowadza w błąd. W celu wyeliminowania wątpliwości otworzyłem problem w Google Tracker:
https://issuetracker.google.com/issues/68908332
jak widzimy, usługa powiązania faktycznie wywołuje transakcję za pomocą segregatora ActivityManager za pośrednictwem segregatorów pamięci podręcznej usługi - śledzę, która usługa jest odpowiedzialna za wiązanie, ale jak widzimy, wynik dla wiązania jest następujący:
transakcja odbywa się za pomocą spoiwa:
Kolejny:
jest to ustawiane w ActivityThread poprzez:
jest to wywoływane w ActivityManagerService w metodzie:
następnie:
ale nie ma pakietu okien i alarmu tylko dla „aktywności”
więc musimy wrócić, aby zadzwonić:
dzięki temu połączenia:
który prowadzi do :
i to jest natywna metoda ....
nie mam teraz czasu, żeby wykopać c, więc dopóki nie rozbiorę wezwania na odpoczynek, zawieszam swoją odpowiedź.
ale najlepszym sposobem sprawdzenia, czy usługa jest uruchomiona, jest utworzenie powiązania (jeśli powiązanie nie zostało utworzone, usługa nie istnieje) - i zapytanie usługi o jej stan za pośrednictwem powiązania (przy użyciu zapisanej flagi wewnętrznej na nim).
aktualizacja 23.06.2018
znalazłem te interesujące:
w skrócie :)
„Zapewnij spoiwo do już powiązanej usługi. Ta metoda jest synchroniczna i nie uruchomi usługi docelowej, jeśli nie jest obecna.”
public IBinder peekService (usługa zamiaru, ciąg znaków resolvedType, ciąg wywołujący pakiet) zgłasza RemoteException;
źródło
Moja konwersja kotlin na
ActivityManager::getRunningServices
podstawie odpowiedzi. Umieść tę funkcję w działaniuźródło
Możesz użyć tej opcji z opcji dla programistów Androida, aby sprawdzić, czy Twoja usługa nadal działa w tle.
źródło
Spokojnie chłopaki ... :)
Myślę, że najbardziej odpowiednim rozwiązaniem jest utrzymanie pary klucz-wartość,
SharedPreferences
czy usługa jest uruchomiona, czy nie.Logika jest bardzo prosta; na dowolnym pożądanym miejscu w klasie usług; wstaw wartość logiczną, która będzie działać jako flaga dla tego, czy usługa jest uruchomiona, czy nie. Następnie przeczytaj tę wartość w dowolnym miejscu w aplikacji.
Przykładowy kod, którego używam w mojej aplikacji, znajduje się poniżej:
W mojej klasie usług (usługa dla strumienia audio) wykonuję następujący kod, gdy usługa jest uruchomiona;
Następnie w dowolnej aktywności mojej aplikacji sprawdzam status usługi za pomocą następującego kodu;
Bez specjalnych uprawnień, bez pętli ... Łatwy sposób, czyste rozwiązanie :)
Jeśli potrzebujesz dodatkowych informacji, zapoznaj się z linkiem
Mam nadzieję że to pomoże.
źródło
onDestroy
nie zawsze jest wywoływany po zabiciu usługi. Na przykład widziałem, jak moje usługi są zabijane w sytuacjach braku pamięci bezonDestroy
wywołania.