Service
to
komponent aplikacji, który potrafi wykonać
długotrwałe operacje w tle, Nie ma interfejsu użytkownika. Jednorazowo
uruchomiono usługę, usługa może być jeszcze uruchomiona przez pewien czas, nawet gdy użytkownik przełączy się na inną;
aplikacji. Dodatkowo komponent można powiązać z usługą, aby wchodzić z nią w interakcję, a nawet wykonywać.
komunikacji międzyprocesowej (IPC). Na przykład usługa może obsługiwać transakcje sieciowe, odtwarzać
muzyki, operacji wejścia-wyjścia plików czy interakcji z dostawcą treści – wszystko to w tle.
Uwaga: usługa działa w głównym wątku hostingu. proces; usługa nie tworzy własnego wątku ani nie jest uruchamiany w oddzielnym procesie, chyba że wskażesz inny. Operacje blokujące należy wykonywać na oddzielny wątek w usłudze, aby uniknąć aplikacji. Błędy ANR (brak odpowiedzi).
Typy usług
Dostępne są trzy różne typy usług:
- Pierwszy plan
-
Usługa na pierwszym planie wykonuje operację, która jest zauważalna dla użytkownika. Na przykład aplikacja audio mogłaby używać usługi na pierwszym planie do odtwarzania ścieżki audio. Usługi działające na pierwszym planie muszą wyświetlać powiadomienie. Usługi działające na pierwszym planie działają nawet wtedy, gdy użytkownik nie wchodzi w interakcję z aplikacją.
Podczas korzystania z usługi na pierwszym planie musisz wyświetlić powiadomienie, aby użytkownicy mają świadomość, że usługa jest uruchomiona. Tego powiadomienia nie można usunąć zostanie odrzucona, chyba że usługa zostanie zatrzymana lub usunięta na pierwszym planie.
Więcej informacji o konfigurowaniu usług działających na pierwszym planie .
Uwaga: atrybut Interfejs WorkManager API zapewnia elastyczny sposób planowania zadań i może uruchomić w razie potrzeby te zadania jako usługi na pierwszym planie. W wielu przypadkach użycie funkcji Usługa WorkManager jest preferowana przy bezpośrednim korzystaniu z usług na pierwszym planie.
- Tło
- Usługa w tle wykonuje operację, która nie jest bezpośrednio wykrywana przez
użytkownika. Jeśli na przykład aplikacja używa usługi, aby zmniejszyć rozmiar pamięci,
co zwykle jest usługą działającą w tle.
Uwaga: jeśli aplikacja jest kierowana na interfejs API na poziomie 26 lub wyższym, system nakłada ograniczenia na działanie w tle. usług, gdy aplikacja nie działa na pierwszym planie. Najwięcej nie zaleca się na przykład uzyskać dostęp do informacji o lokalizacji z . Zamiast tego: planowania zadań za pomocą WorkManager.
- Powiązanie
- Usługa jest powiązana, gdy komponent aplikacji wiąże się z nią przez wywołanie
bindService()
. Powiązana usługa oferuje klient-serwer interfejs, który pozwala komponentom na interakcję z usługą, wysyłanie żądań, odbieranie wyników a nawet między procesami w ramach komunikacji międzyprocesowej (IPC). Powiązana usługa działa tylko o ile jest z nim powiązany inny komponent aplikacji. Komponent może być powiązany z wieloma komponentami ale gdy wszystkie zostaną usunięte, usługa zostanie zniszczona.
W tej dokumentacji ogólnie omawiamy oddzielnie usługi rozpoczęte i powiązane,
może działać w obie strony – może być uruchamiana (aby działać bezterminowo) i umożliwiać
i powiązania. Trzeba tylko określić, czy wdrożysz kilka metod wywołania zwrotnego: onStartCommand()
, aby zezwolić komponentom na jej uruchomienie, i onBind()
, aby umożliwić powiązanie.
Niezależnie od tego, czy usługa jest uruchomiona, powiązana czy też oba te elementy
mogą korzystać z usługi (nawet z oddzielnej aplikacji) w taki sam sposób, jak każdy komponent
aktywność, rozpoczynając ją od elementu Intent
. Możesz jednak zadeklarować
ustaw usługę jako prywatną w pliku manifestu i zablokuj dostęp innym aplikacjom.
Jest to omówione dokładniej w sekcji dotyczącej deklarowania usługi w
pliku manifestu.
Wybór między usługą a wątkiem
Usługa to po prostu komponent, który może działać w tle, nawet jeśli użytkownik nie podczas interakcji z aplikacją, więc usługi należy tworzyć tylko wtedy, potrzeby.
Musisz wykonać pracę poza wątkiem głównym, ale tylko w czasie, gdy użytkownik wchodzi w interakcję
z Twoją aplikacją, zamiast tego utwórz nowy wątek w kontekście innej aplikacji.
. Jeśli na przykład chcesz posłuchać muzyki, ale tylko podczas trwania aktywności,
możesz utworzyć wątek w onCreate()
,
zacznij go uruchamiać za onStart()
,
i zatrzymaj go za onStop()
.
Rozważ też użycie pul wątków i wykonawców z pakietu java.util.concurrent
lub współrzędnych Kotlin zamiast tradycyjnych
Thread
zajęcia. Zobacz
Dokument Threading on Android (Wątki na Androidzie),
do wątków w tle.
Pamiętaj, że jeśli korzystasz z usługi, jest ona nadal uruchomiona w głównym wątku aplikacji przez domyślnie, więc należy utworzyć nowy wątek w usłudze, jeśli jest on intensywny lub operacji blokujących.
Podstawy
Aby utworzyć usługę, musisz utworzyć podklasę Service
lub użyć podklasy
istniejących podklas. W swojej implementacji musisz zastąpić niektóre metody wywołania zwrotnego, które
obsługuje kluczowe aspekty cyklu życia usługi i udostępnia mechanizm, który pozwala komponentom
powiązane z usługą w razie potrzeby. Oto najważniejsze metody wywołania zwrotnego, które należy
zastąp:
onStartCommand()
- System wywołuje tę metodę, wywołując metodę
startService()
, gdy inny komponent (np. aktywność) prosi o uruchomienie usługi. Po wykonaniu tej metody usługa jest uruchamiana i może być uruchamiana w tle przez czas nieokreślony. Jeśli wdrożysz to rozwiązanie, ponosisz odpowiedzialność za zatrzymanie usługi, gdy jego praca zostanie zakończona, wywołując funkcjęstopSelf()
lubstopService()
. Jeśli chcesz podać tylko powiązanie, którzy muszą wdrożyć tę metodę. onBind()
- System wywołuje tę metodę, wywołując metodę
bindService()
, gdy inny komponent chce utworzyć powiązanie z usługą (np. w celu wykonania RPC). Implementując tę metodę, musisz udostępnić interfejs, który klient komunikuje się z usługą przez zwrócenieIBinder
. Zawsze musisz wdrożyć tę metodę, Jeśli jednak nie chcesz zezwalać na powiązanie, zwróć wartość null. onCreate()
- System wywołuje tę metodę, aby przeprowadzić jednorazowe procedury konfiguracji, gdy usługa jest
utworzony (zanim wywoła
onStartCommand()
lubonBind()
). Jeśli usługa jest już uruchomiona, ta metoda nie jest . onDestroy()
- System wywołuje tę metodę, gdy usługa nie jest już używana i jest niszczona. Usługa powinna wdrożyć to rozwiązanie, aby wyczyścić wszelkie zasoby, takie jak wątki, zarejestrowane, słuchacze czy odbiorniki. Jest to ostatnie wywołanie usługi.
Jeśli komponent uruchamia usługę, wywołując metodę startService()
(co skutkuje wywołaniem onStartCommand()
), usługa
będzie działać, dopóki się nie zatrzyma przy użyciu parametru stopSelf()
lub innego
zatrzymuje go, wywołując metodę stopService()
.
Jeśli komponent wywołuje
bindService()
w celu utworzenia usługi, a usługa onStartCommand()
nie jest wywoływana, usługa działa
dopóki komponent będzie z nim powiązany. Gdy usługa zostanie usunięta ze wszystkich klientów,
system zniszczy ją.
System Android zatrzymuje usługę tylko wtedy, gdy ilość pamięci jest niska i musi przywrócić system
zasobów związanych z aktywnością
ukierunkowaną na użytkownika. Jeśli usługa jest powiązana z działaniem, dla którego występuje użytkownik
uwaga, prawdopodobieństwo śmierci jest mniejsze. jeśli usługa jest zadeklarowana do uruchamiania na pierwszym planie, rzadko jest wyłączana.
Jeśli usługa została uruchomiona i działa od dłuższego czasu, system obniży jej pozycję
znajduje się na liście zadań w tle w czasie, przez co usługa jest bardzo podatna na
likwidacja – jeśli usługa jest uruchomiona, musisz zaprojektować ją tak, aby płynnie obsługiwać ponowne uruchomienia.
przez system. Jeśli system zakończy działanie usługi, uruchomi ją ponownie, gdy tylko zasoby przestaną być dostępne
dostępna, ale zależy to również od wartości zwracanej z narzędzia onStartCommand()
. Więcej informacji na temat konfiguracji
o tym, kiedy system może zniszczyć usługę, zapoznaj się z sekcją Procesy i wątki.
dokument.
W kolejnych sekcjach dowiesz się, jak utworzyć
startService()
i
bindService()
metod usługi oraz instrukcje korzystania
ich z innych komponentów aplikacji.
Deklarowanie usługi w pliku manifestu
Musisz zadeklarować wszystkie usługi w aplikacji pliku manifestu, tak jak w przypadku działań i innych komponentów.
Aby zadeklarować usługę, dodaj element <service>
jako dziecko grupy <application>
. Oto przykład:
<manifest ... > ... <application ... > <service android:name=".ExampleService" /> ... </application> </manifest>
Zobacz element <service>
odniesienia, aby dowiedzieć się więcej o deklarowaniu usługi w pliku manifestu.
W elemencie <service>
możesz też dodawać inne atrybuty, aby
określić właściwości, takie jak uprawnienia wymagane do uruchomienia usługi oraz proces
w której ma być uruchomiona usługa. android:name
jest jedynym wymaganym atrybutem – określa nazwę klasy usługi. Po
po opublikowaniu aplikacji nie zmieniaj nazwy, aby zapobiec uszkodzeniu
z powodu zależności od wyraźnych intencji uruchomienia lub powiązania usługi (przeczytaj post na blogu Things)
Tego nie można zmienić).
Uwaga: aby mieć pewność, że aplikacja jest bezpieczna, zawsze używaj parametru
jawna intencja, gdy uruchamiasz Service
i nie deklaruj filtrów intencji dla
z Twoich usług. Użycie intencji niejawnej do uruchomienia usługi stanowi zagrożenie dla bezpieczeństwa, ponieważ nie można
mieć pewność co do usługi, która odpowiada na intencję, a użytkownik nie będzie wiedzieć, która usługa
zaczyna się. Począwszy od Androida 5.0 (poziom interfejsu API 21) system zgłasza wyjątek, gdy wywołujesz
bindService()
z intencją niejawną.
Aby upewnić się, że usługa jest dostępna tylko dla Twojej aplikacji,
w tym android:exported
i ustawiając go na false
. Spowoduje to, że inne aplikacje nie będą uruchamiać Twojego
nawet w przypadku użycia wyraźnej intencji.
Uwaga:
Użytkownicy mogą sprawdzić, jakie usługi są uruchomione na ich urządzeniach. Jeśli zobaczą
usługi, której nie rozpoznają lub której nie ufają, może ją zatrzymać. W
aby uniknąć przypadkowego zatrzymania usługi przez użytkowników, musisz
aby dodać
android:description
do atrybutu
<service>
element manifestu aplikacji. W opisie:
opisz krótko, do czego służy usługa i jakie są jej zalety.
co zapewnia.
Tworzenie uruchomionej usługi
Uruchomiona usługa to taka, której inny komponent uruchamia się przez wywołanie metody startService()
, co skutkuje wywołaniem funkcji
Metoda onStartCommand()
.
Po uruchomieniu usługi jej cykl życia jest niezależny od
który ją zainicjował. Usługa może działać w tle bez końca, nawet jeśli
komponent, który go uruchomił, zostaje zniszczony. W związku z tym usługa powinna zatrzymać się samodzielnie, gdy wykonywane jest zadanie
można zakończyć, wywołując funkcję stopSelf()
lub inny komponent może
aby zatrzymać tę funkcję, zadzwoń pod numer stopService()
.
Komponent aplikacji, taki jak działanie, może uruchomić usługę, wywołując funkcję startService()
i przekazując Intent
, który określa usługę i zawiera wszelkie jej dane. Usługa otrzymuje
ten Intent
w metodzie onStartCommand()
.
Załóżmy na przykład, że działanie musi zapisać część danych w bazie danych online. Aktywność
może uruchomić usługę towarzyszącą i dostarczyć jej dane do zapisania, przekazując intencję do funkcji startService()
. Usługa odbiera intencję w języku onStartCommand()
, łączy się z internetem i wykonuje
transakcji w bazie danych. Po zakończeniu transakcji usługa zatrzymuje się samoczynnie,
zniszczenia.
Uwaga: usługa działa w ramach tego samego procesu co aplikacja. w którym jest ona zadeklarowana i domyślnie w głównym wątku aplikacji. Jeśli Twoja usługa wykonuje intensywne lub blokujące działanie, gdy użytkownik wchodzi w interakcję z tym samym działaniem aplikacji, usługa spowalnia wydajność działań. Aby uniknąć wpływu na korzystanie z aplikacji wydajności, rozpocznij nowy wątek w usłudze.
Klasa Service
jest podstawą.
dla wszystkich usług. Rozszerzając te zajęcia, ważne jest utworzenie nowego wątku, w którym
usługa może wykonać wszystkie zadania; usługa używa głównego wątku aplikacji przez
domyślnie, co może spowolnić wszystkie działania wykonywane przez Twoją aplikację.
Platforma Androida zapewnia również IntentService
podklasa klasy Service
, która korzysta z funkcji
wątku roboczego do obsługi wszystkich żądań startowych, pojedynczo. Korzystanie z tych zajęć nie jest
zalecamy w przypadku nowych aplikacji, ponieważ początkowo nie będzie działać prawidłowo na Androidzie 8 Oreo.
Wprowadzenie limitów wykonywania w tle.
Poza tym w przypadku Androida 11 wycofaliśmy tę funkcję.
Usługi JobIntentService możesz użyć jako
zamiennik na telefon IntentService
, który jest zgodny z nowszymi wersjami Androida.
W poniższych sekcjach opisano, jak wdrożyć własną usługę niestandardową, ale należy w większości przypadków zalecamy korzystanie z WorkManagera. Zapoznaj się z przewodnikiem po przetwarzaniu w tle na Androidzie. aby przekonać się, czy znajdziemy rozwiązanie odpowiednie do Twoich potrzeb.
Rozszerzanie klasy usługi
Możesz przedłużyć zajęcia Service
która obsługuje każdą intencję przychodzącą. Podstawowa implementacja może wyglądać tak:
Kotlin
class HelloService : Service() { private var serviceLooper: Looper? = null private var serviceHandler: ServiceHandler? = null // Handler that receives messages from the thread private inner class ServiceHandler(looper: Looper) : Handler(looper) { override fun handleMessage(msg: Message) { // Normally we would do some work here, like download a file. // For our sample, we just sleep for 5 seconds. try { Thread.sleep(5000) } catch (e: InterruptedException) { // Restore interrupt status. Thread.currentThread().interrupt() } // Stop the service using the startId, so that we don't stop // the service in the middle of handling another job stopSelf(msg.arg1) } } override fun onCreate() { // Start up the thread running the service. Note that we create a // separate thread because the service normally runs in the process's // main thread, which we don't want to block. We also make it // background priority so CPU-intensive work will not disrupt our UI. HandlerThread("ServiceStartArguments", Process.THREAD_PRIORITY_BACKGROUND).apply { start() // Get the HandlerThread's Looper and use it for our Handler serviceLooper = looper serviceHandler = ServiceHandler(looper) } } override fun onStartCommand(intent: Intent, flags: Int, startId: Int): Int { Toast.makeText(this, "service starting", Toast.LENGTH_SHORT).show() // For each start request, send a message to start a job and deliver the // start ID so we know which request we're stopping when we finish the job serviceHandler?.obtainMessage()?.also { msg -> msg.arg1 = startId serviceHandler?.sendMessage(msg) } // If we get killed, after returning from here, restart return START_STICKY } override fun onBind(intent: Intent): IBinder? { // We don't provide binding, so return null return null } override fun onDestroy() { Toast.makeText(this, "service done", Toast.LENGTH_SHORT).show() } }
Java
public class HelloService extends Service { private Looper serviceLooper; private ServiceHandler serviceHandler; // Handler that receives messages from the thread private final class ServiceHandler extends Handler { public ServiceHandler(Looper looper) { super(looper); } @Override public void handleMessage(Message msg) { // Normally we would do some work here, like download a file. // For our sample, we just sleep for 5 seconds. try { Thread.sleep(5000); } catch (InterruptedException e) { // Restore interrupt status. Thread.currentThread().interrupt(); } // Stop the service using the startId, so that we don't stop // the service in the middle of handling another job stopSelf(msg.arg1); } } @Override public void onCreate() { // Start up the thread running the service. Note that we create a // separate thread because the service normally runs in the process's // main thread, which we don't want to block. We also make it // background priority so CPU-intensive work doesn't disrupt our UI. HandlerThread thread = new HandlerThread("ServiceStartArguments", Process.THREAD_PRIORITY_BACKGROUND); thread.start(); // Get the HandlerThread's Looper and use it for our Handler serviceLooper = thread.getLooper(); serviceHandler = new ServiceHandler(serviceLooper); } @Override public int onStartCommand(Intent intent, int flags, int startId) { Toast.makeText(this, "service starting", Toast.LENGTH_SHORT).show(); // For each start request, send a message to start a job and deliver the // start ID so we know which request we're stopping when we finish the job Message msg = serviceHandler.obtainMessage(); msg.arg1 = startId; serviceHandler.sendMessage(msg); // If we get killed, after returning from here, restart return START_STICKY; } @Override public IBinder onBind(Intent intent) { // We don't provide binding, so return null return null; } @Override public void onDestroy() { Toast.makeText(this, "service done", Toast.LENGTH_SHORT).show(); } }
Przykładowy kod obsługuje wszystkie połączenia przychodzące w aplikacji onStartCommand()
i publikuje pracę w Handler
działającym w wątku w tle. Działa on jak IntentService
i przetwarza wszystkie żądania po kolei, po kolei.
Możesz zmienić kod, aby uruchomić tę pracę na puli wątków, jeśli na przykład chcesz uruchamiać wiele żądań jednocześnie.
Zwróć uwagę, że metoda onStartCommand()
musi zwracać błąd
liczba całkowita. Liczba całkowita to wartość opisująca, w jaki sposób system powinien kontynuować działanie usługi w
gdy system go zabije. Wartość zwrócona
z onStartCommand()
musi mieć jedną z tych wartości
stałe:
START_NOT_STICKY
- Jeśli po zwróceniu usługi
onStartCommand()
system zamknie usługę, nie odtwarzaj jej ponownie, chyba że trwa oczekiwanie co chcesz osiągnąć. To najbezpieczniejszy sposób uniknięcia uruchamiania usługi, gdy nie jest to konieczne i kiedy aplikacja może po prostu ponownie uruchomić nieukończone zadania. START_STICKY
- Jeśli system wyłączy usługę po zwróceniu
onStartCommand()
, utwórz ponownie usługę i wywołaj funkcjęonStartCommand()
, ale nie przesyłaj ponownie ostatniej intencji. Zamiast tego system wywołuje metodęonStartCommand()
, używając parametru intencję null, chyba że istnieją oczekujące intencje na uruchomienie usługi. W takim przypadku i realizować te intencje. Jest to odpowiednie dla odtwarzaczy multimedialnych (lub podobnych usług), które nie wykonując polecenia, ale działają bezterminowo i oczekują na zadanie. START_REDELIVER_INTENT
- Jeśli system wyłączy usługę po powrocie usługi
onStartCommand()
, utwórz ją ponownie i wywołaj usługęonStartCommand()
z ostatnią intencją przesłaną do posprzedażna. Wszystkie oczekujące intencje są dostarczane. Jest to odpowiednie dla usług, które są: wykonywanie zadania, które powinno zostać natychmiast wznowione, np. pobranie pliku.
Więcej informacji o tych zwracanych wartościach znajdziesz w materiałach, do których znajdziesz link dokumentacji dla każdej stałej.
Uruchamianie usługi
Usługę możesz uruchomić z poziomu działania lub innego komponentu aplikacji przez
z wynikiem pozytywnym: Intent
do: startService()
lub startForegroundService()
.
System Android wywołuje metodę onStartCommand()
usługi i przekazuje jej Intent
,
, który określa usługę, która ma zostać uruchomiona.
Uwaga: jeśli aplikacja jest kierowana na interfejs API na poziomie 26 lub wyższym, system
nakłada ograniczenia na używanie lub tworzenie usług w tle, chyba że aplikacja
nawet na pierwszym planie. Jeśli aplikacja musi utworzyć usługę na pierwszym planie,
aplikacja powinna wywołać funkcję startForegroundService()
. Ta metoda tworzy usługę w tle, ale
zasygnalizuje systemowi, że usługa będzie promować się wśród
na pierwszym planie. Po utworzeniu usługa musi wywołać swój
startForeground()
metoda w:
pięć sekund.
Na przykład działanie może uruchomić przykładową usługę z poprzedniej sekcji (HelloService
) przy użyciu jednoznacznej intencji z parametrem startService()
, jak w tym przykładzie:
Kotlin
startService(Intent(this, HelloService::class.java))
Java
startService(new Intent(this, HelloService.class));
Metoda startService()
zwraca natychmiast, a
system Android wywołuje metodę onStartCommand()
usługi. Jeśli usługa nie jest jeszcze uruchomiona, system najpierw wywołuje metodę onCreate()
, a następnie –
onStartCommand()
Jeśli usługa nie zapewnia też powiązania, intencja dostarczana za pomocą funkcji startService()
jest jedynym trybem komunikacji między
komponent aplikacji i usługa. Jeśli jednak chcesz, aby usługa odsyłała wyniki,
klient, który uruchamia usługę, może utworzyć PendingIntent
dla transmisji
(z firmą getBroadcast()
) i dostarcz je do usługi
w: Intent
, który uruchamia usługę. Usługa może następnie używać
aby dostarczyć wynik.
Kolejne żądania uruchomienia usługi powodują wiele powiązanych wywołań usługi
onStartCommand()
Trzeba jednak wysłać tylko jedną prośbę o zatrzymanie.
usługa (z stopSelf()
lub stopService()
) jest wymagana do jej zatrzymania.
Zatrzymywanie usługi
Uruchomiona usługa musi zarządzać własnym cyklem życia. Oznacza to, że system nie zatrzymuje się ani
zniszczenie usługi, chyba że musi ona odzyskać pamięć systemową i usługę
będzie nadal działać po powrocie funkcji onStartCommand()
.
usługa musi się zatrzymać, wywołując metodę stopSelf()
lub inną
może go zatrzymać, wywołując metodę stopService()
.
Gdy pojawi się prośba o zatrzymanie usługi stopSelf()
lub stopService()
, system zniszczy ją natychmiast
jak to tylko możliwe.
Jeśli Twoja usługa obsługuje jednocześnie wiele żądań wysyłanych do onStartCommand()
, nie zatrzymuj funkcji
po zakończeniu przetwarzania żądania rozpoczęcia, ponieważ mogło dojść do
start żądania (zatrzymanie na końcu pierwszego żądania spowoduje zakończenie drugiego). Aby unikać
ten problem, możesz skorzystać z stopSelf(int)
, by upewnić się, że prośba do
zatrzymywanie usługi jest zawsze określane na podstawie ostatniego żądania uruchomienia. Oznacza to, że wywołując metodę stopSelf(int)
, przekazujesz identyfikator żądania startowego (startId
dostarczone do onStartCommand()
), do którego zostało wysłane żądanie zatrzymania
. Następnie, jeśli usługa otrzyma nowe żądanie startowe, zanim będzie można wywołać funkcję stopSelf(int)
, identyfikator nie będzie się zgadzać, a usługa nie przestanie działać.
Uwaga: aby nie marnować zasobów systemu i nie zużywać
baterii, upewnij się, że po zakończeniu pracy aplikacja przestanie działać.
W razie potrzeby inne komponenty mogą zatrzymać usługę, wywołując funkcję stopService()
. Nawet jeśli włączysz powiązanie dla usługi,
jeśli otrzymasz połączenie z numerem onStartCommand()
, musisz zawsze samodzielnie zatrzymywać usługę.
Więcej informacji o cyklu życia usługi znajdziesz w sekcji Zarządzanie cyklem życia usługi poniżej.
Tworzenie powiązanej usługi
Powiązana usługa to usługa, która umożliwia komponentom aplikacji powiązanie z nią przez wywołanie funkcji bindService()
w celu utworzenia długotrwałego połączenia.
Zwykle nie zezwala komponentom na uruchomienie go przez wywołanie metody startService()
.
Utwórz powiązaną usługę, gdy chcesz korzystać z usługi na podstawie działań i innych komponentów aplikacji, ani do udostępniania niektórych jej funkcji w innych aplikacjach przy użyciu komunikacji międzyprocesowej (IPC).
Aby utworzyć powiązaną usługę, zaimplementuj metodę wywołania zwrotnego onBind()
, która zwraca żądanie IBinder
, które
definiuje interfejs komunikacji z usługą. Inne komponenty aplikacji mogą wtedy wywoływać metodę
bindService()
, aby pobrać interfejs oraz
rozpocząć wywoływanie metod w usłudze. Usługa działa jedynie, aby obsługiwać komponent aplikacji, który
więc gdy nie są z nią powiązane żadne komponenty, system ją zniszczy.
Nie musisz zatrzymywać powiązanej usługi w taki sam sposób, w jaki jest to konieczne, gdy usługa jest
rozpoczęto do onStartCommand()
.
Aby utworzyć powiązaną usługę, musisz zdefiniować interfejs określający, jak klient może
komunikują się z usługą. Ten interfejs między usługą
, a klient musi być implementacją IBinder
. To właśnie musi być implementacja
metody wywołania zwrotnego onBind()
. Gdy klient otrzyma IBinder
, może się rozpocząć
podczas interakcji z usługą za pośrednictwem tego interfejsu.
Z usługą może być powiązanych jednocześnie wiele klientów. Gdy klient zakończy interakcję z
usługi, wywołuje metodę unbindService()
, aby usunąć powiązanie.
Jeśli z usługą nie są powiązane żadne klienty, system zniszczy tę usługę.
Istnieje wiele sposobów implementacji powiązanej usługi, a implementacja jest bardziej niż w przypadku uruchomienia usługi. Z tego powodu dyskusja dotycząca powiązanej usługi pojawia się w oddzielny dokument na temat usług granicznych.
Wysyłanie powiadomień do użytkownika
Gdy usługa jest uruchomiona, może powiadamiać użytkowników o zdarzeniach za pomocą powiadomień na pasku powiadomień lub powiadomień na pasku stanu.
Powiadomienie na pasku powiadomień to wiadomość wyświetlana na powierzchni bieżącego okna tylko przez chwilę przed zniknięciem. Na pasku stanu powiadomienie zawiera ikonę z który użytkownik może wybrać, aby wykonać działanie (np. rozpocząć aktywność).
Powiadomienia na pasku stanu zazwyczaj najlepiej sprawdzają się, gdy w tle działają takie funkcje jak pobieranie pliku i użytkownik może wykonać na nim czynności. Gdy użytkownik wybierze powiadomienie z widoku rozwiniętego, powiadomienie może rozpocząć aktywność (na przykład aby wyświetlić pobrany plik).
Zarządzanie cyklem życia usługi
Cykl życia usługi jest znacznie prostszy niż w przypadku działania. Jednak jest to jeszcze bardziej musisz dokładnie przemyśleć sposób tworzenia i niszczenia usługi, ponieważ może działać w tle bez wiedzy użytkownika.
Cykl życia usługi – od momentu utworzenia do momentu zniszczenia – może być śledzony jedną z tych 2 ścieżek:
- Uruchomiona usługa
Usługa jest tworzona, gdy inny komponent wywołuje
startService()
. Usługa działa bezterminowo i musi zatrzymać się, wywołującstopSelf()
. Inny komponent może też zatrzymać usłudze, dzwoniąc pod numerstopService()
. Po zatrzymaniu usługa system zniszczy ją. - Powiązana usługa
Usługa jest tworzona, gdy inny komponent (klient) wywoła funkcję
bindService()
. Klient komunikuje się z usługą. korzystając z interfejsuIBinder
. Klient może zamknąć połączenie, wywołującunbindService()
Związań może być wielu klientów tę samą usługę, a po usunięciu powiązania przez wszystkie system niszczy usługę. Usługa nie musi się zatrzymywać.
Te 2 ścieżki nie są całkowicie odrębne. Możesz utworzyć powiązanie z usługą, która jest już
rozpoczyna się od startService()
. Możesz na przykład:
uruchomić usługę muzyki w tle, wywołując funkcję startService()
przy użyciu identyfikatora Intent
identyfikującego muzykę, która ma być odtwarzana. Później
– np. gdy użytkownik chce mieć większą kontrolę nad odtwarzaczem lub uzyskać informacje na temat
obecnie utwór, działanie może zostać powiązane z usługą przez wywołanie metody bindService()
. W takich przypadkach stopService()
lub stopSelf()
nie zatrzymuje usługi, dopóki powiązanie wszystkich klientów nie zostanie usunięte.
Wdrażanie wywołań zwrotnych cyklu życia
Tak jak w przypadku działania, usługa ma metody wywołania zwrotnego cyklu życia, które możesz wdrożyć w celu monitorowania zmian stanu usługi i wykonywania pracy w odpowiednich momentach. Następujący szkielet przedstawia każdą z metod cyklu życia:
Kotlin
class ExampleService : Service() { private var startMode: Int = 0 // indicates how to behave if the service is killed private var binder: IBinder? = null // interface for clients that bind private var allowRebind: Boolean = false // indicates whether onRebind should be used override funonCreate
() { // The service is being created } override funonStartCommand
(intent: Intent?, flags: Int, startId: Int): Int { // The service is starting, due to a call to startService() return startMode } override funonBind
(intent: Intent): IBinder? { // A client is binding to the service with bindService() return binder } override funonUnbind
(intent: Intent): Boolean { // All clients have unbound with unbindService() return allowRebind } override funonRebind
(intent: Intent) { // A client is binding to the service with bindService(), // after onUnbind() has already been called } override funonDestroy
() { // The service is no longer used and is being destroyed } }
Java
public class ExampleService extends Service { int startMode; // indicates how to behave if the service is killed IBinder binder; // interface for clients that bind boolean allowRebind; // indicates whether onRebind should be used @Override public voidonCreate
() { // The service is being created } @Override public intonStartCommand
(Intent intent, int flags, int startId) { // The service is starting, due to a call tostartService()
return startMode; } @Override public IBinderonBind
(Intent intent) { // A client is binding to the service withbindService()
return binder; } @Override public booleanonUnbind
(Intent intent) { // All clients have unbound withunbindService()
return allowRebind; } @Override public voidonRebind
(Intent intent) { // A client is binding to the service withbindService()
, // after onUnbind() has already been called } @Override public voidonDestroy
() { // The service is no longer used and is being destroyed } }
Uwaga: w przeciwieństwie do metod wywołania zwrotnego cyklu życia aktywności nie jest wymagane do wywoływania implementacji superklasy tych metod wywołania zwrotnego.
Rysunek 2 przedstawia typowe metody wywołania zwrotnego dla usługi. Chociaż widać tu różnicę
usług utworzonych przez startService()
na podstawie tych
autor: bindService()
, zachowaj
pamiętaj, że każda usługa, niezależnie od tego, jak działa, może umożliwić klientom powiązanie z nią.
Usługa, która została pierwotnie uruchomiona w usłudze onStartCommand()
(przez klienta wywołującego startService()
)
może odbierać połączenia z numerem onBind()
(gdy klient nawiąże połączenie
bindService()
).
Dzięki wdrożeniu tych metod możesz monitorować te dwie zagnieżdżone pętle usługi cykl życia:
- Cały okres usługi następuje od momentu wywołania funkcji
onCreate()
do czasu powrotu funkcjionDestroy()
. Tak jak w przypadku działania, usługa przeprowadza wstępną konfigurację w:onCreate()
i zwolni wszystkie pozostałe zasoby w regionieonDestroy()
. Na przykład plik usługa odtwarzania muzyki może utworzyć wątek, w którym muzyka jest odtwarzana w usłudzeonCreate()
, a następnie zatrzymać wątek w usłudzeonDestroy()
.Uwaga:
onCreate()
i metodonDestroy()
są wywoływane dla wszystkich usług, niezależnie od tego, utworzone przez:startService()
lubbindService()
. - Aktywny czas życia usługi zaczyna się od wywołania
onStartCommand()
lubonBind()
. Dla każdej metody przekazywana jest wartośćIntent
, która została przekazana dostartService()
lubbindService()
.Jeśli usługa zostanie uruchomiona, aktywny okres życia zakończy się w tym samym momencie, w którym został kończy się (usługa jest nadal aktywna nawet po powrocie produktu
onStartCommand()
). Jeśli usługa jest powiązana, aktywny okres życia kończy się, gdy powracaonUnbind()
.
Uwaga: mimo że uruchomiona usługa jest zatrzymywana przez wywołanie funkcji
stopSelf()
lub stopService()
, nie ma odpowiedniego wywołania zwrotnego dla
(nie ma wywołania zwrotnego onStop()
). O ile usługa nie jest powiązana z klientem,
system zniszczy ją po zatrzymaniu usługi – jedynym otrzymanym wywołaniem zwrotnym jest onDestroy()
.
Więcej informacji o tworzeniu usługi tworzącej powiązania znajdziesz w dokumencie Usługi graniczne.
który zawiera więcej informacji na temat onRebind()
metody wywołania zwrotnego w sekcji Zarządzanie cyklem życia
w powiązanej usłudze.