Przegląd usług

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() lub stopService(). 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ócenie IBinder. 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() lub onBind()). 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ąc stopSelf(). Inny komponent może też zatrzymać usłudze, dzwoniąc pod numer stopService(). 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 interfejsu IBinder. Klient może zamknąć połączenie, wywołując unbindService() 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 fun onCreate() {
        // The service is being created
    }

    override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
        // The service is starting, due to a call to startService()
        return startMode
    }

    override fun onBind(intent: Intent): IBinder? {
        // A client is binding to the service with bindService()
        return binder
    }

    override fun onUnbind(intent: Intent): Boolean {
        // All clients have unbound with unbindService()
        return allowRebind
    }

    override fun onRebind(intent: Intent) {
        // A client is binding to the service with bindService(),
        // after onUnbind() has already been called
    }

    override fun onDestroy() {
        // 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 void onCreate() {
        // The service is being created
    }
    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        // The service is starting, due to a call to startService()
        return startMode;
    }
    @Override
    public IBinder onBind(Intent intent) {
        // A client is binding to the service with bindService()
        return binder;
    }
    @Override
    public boolean onUnbind(Intent intent) {
        // All clients have unbound with unbindService()
        return allowRebind;
    }
    @Override
    public void onRebind(Intent intent) {
        // A client is binding to the service with bindService(),
        // after onUnbind() has already been called
    }
    @Override
    public void onDestroy() {
        // 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. Cykl życia usługi. Schemat po lewej pokazuje cykl życia usługi przy użyciu startService(), a diagram po prawej stronie przedstawia cykl życia usługi. dzięki bindService().

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 funkcji onDestroy(). Tak jak w przypadku działania, usługa przeprowadza wstępną konfigurację w: onCreate() i zwolni wszystkie pozostałe zasoby w regionie onDestroy(). Na przykład plik usługa odtwarzania muzyki może utworzyć wątek, w którym muzyka jest odtwarzana w usłudze onCreate(), a następnie zatrzymać wątek w usłudze onDestroy().

    Uwaga: onCreate() i metod onDestroy() są wywoływane dla wszystkich usług, niezależnie od tego, utworzone przez: startService() lub bindService().

  • Aktywny czas życia usługi zaczyna się od wywołania onStartCommand() lub onBind(). Dla każdej metody przekazywana jest wartość Intent, która została przekazana do startService() lub bindService().

    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 powraca onUnbind().

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.