Powiązana usługa to serwer w interfejsie klient-serwer. Umożliwia komponentom takich jak działania powiązane z usługą, wysyłanie żądań, otrzymywanie odpowiedzi komunikacji międzyprocesowej (IPC). Powiązana usługa zwykle działa tylko wtedy, gdy obsługuje inną aplikacji i nie działa w tle w nieskończoność.
Ten dokument opisuje sposób tworzenia powiązanej usługi, w tym sposobów tworzenia powiązania. z innych komponentów aplikacji. Dodatkowe informacje na temat usług dostępnych w ogólne, takie jak sposób dostarczania powiadomień z usługi i konfigurowanie jej tak, aby działała na pierwszym planie, zapoznaj się z Omówienie usług.
Podstawy
Powiązana usługa to implementacja klasy Service
, która umożliwia
inne aplikacje łączą go z nim i wchodzą z nim w interakcję. Aby udostępnić powiązanie dla
zaimplementujesz metodę wywołania zwrotnego onBind()
. Ten
zwraca obiekt IBinder
, który definiuje interfejs programowania,
których klienci mogą używać do interakcji z usługą.
Powiąż z uruchomioną usługą
Jak wspominaliśmy w sekcji Omówienie usług,
możesz utworzyć usługę, która jest zarówno rozpoczęta, jak i powiązana. Oznacza to, że możesz rozpocząć
usłudze, wywołując metodę startService()
. Zapewnia to
świadczenie usługi w nieskończoność. Możesz też pozwolić klientowi na powiązanie z usługą przez
Dzwonię pod bindService()
.
Jeśli zezwolisz na uruchomienie i powiązanie usługi, po jej uruchomieniu
system nie zniszczy usługi po usunięciu powiązania wszystkich klientów.
Zamiast tego musisz:
wyraźnie zatrzymaj usługę, wywołując metodę stopSelf()
lub stopService()
.
Chociaż zazwyczaj implementujesz onBind()
lub onStartCommand()
, czasami jest
niezbędne do
implementować oba te typy. Na przykład w odtwarzaczu muzycznym może się przydać, by umożliwić działanie usługi,
w nieskończoność, a także wiązania. W ten sposób działanie może uruchomić usługę w celu odtwarzania
muzyka, która będzie odtwarzana nawet wtedy, gdy użytkownik wyjdzie z aplikacji. Następnie, gdy użytkownik
wraca do aplikacji, działanie może zostać powiązane z usługą, aby odzyskać kontrolę nad
odtwarzania.
Aby uzyskać więcej informacji o cyklu życia usługi podczas dodawania powiązania do uruchomionej usługi, zobacz sekcję Zarządzanie cyklem życia powiązanej usługi.
Klient tworzy powiązanie z usługą przez wywołanie
bindService()
W takim przypadku musi
udostępniają implementację tagu ServiceConnection
, który
monitoruje połączenie z usługą. Wartość zwrócona dla
bindService()
wskazuje, czy
czy istnieje żądana usługa oraz czy klient ma do niej dostęp.
Kiedy
Android tworzy połączenie między klientem a usługą,
dzwoni do: onServiceConnected()
– ServiceConnection
.
Metoda onServiceConnected()
zawiera IBinder
argumentu, którego klient używa następnie do komunikowania się z powiązaną usługą.
Z usługą możesz połączyć wielu klientów jednocześnie. Jednak
system zapisuje w pamięci podręcznej kanał komunikacji usługi IBinder
.
Inaczej mówiąc, system wywołuje metodę onBind()
usługi
do wygenerowania IBinder
tylko wtedy, gdy pierwszy
klientów. System dostarcza następnie ten sam IBinder
do:
wszystkich dodatkowych klientów powiązanych z tą samą usługą, bez konieczności
onBind()
.
Gdy ostatni klient usunie powiązanie z usługą, system zniszczy usługę, chyba że
usługa została uruchomiona przy użyciu startService()
.
Najważniejszym elementem implementacji powiązanej usługi jest zdefiniowanie interfejsu
którą zwraca metoda wywołania zwrotnego onBind()
. Poniżej
zawiera omówienie kilku sposobów definiowania
Interfejs IBinder
.
Utwórz powiązaną usługę
Podczas tworzenia usługi zapewniającej powiązanie musisz podać IBinder
udostępnia interfejs programowania, za pomocą którego klienci mogą korzystać z usługi. OK
można zdefiniować interfejs na 3 sposoby:
- Rozszerzanie klasy Binder
- Jeśli usługa jest prywatna dla Twojej aplikacji i działa w tym samym procesie
jako klient, co jest typowe, utwórz interfejs, rozszerzając
Binder
zajęcia i zwrócenie jego instancji zonBind()
Klient otrzymujeBinder
i może go używać, aby uzyskać bezpośredni dostęp do metod publicznych dostępnych wBinder
lubService
.Jest to preferowana technika, gdy usługa jest jedynie robotem działającym w tle aplikacji. Jedynym przypadkiem użycia, w którym nie jest to preferowany sposób tworzenia interfejsu, jeśli z usługi korzystają inne aplikacje lub procesy.
- Korzystanie z czatu
- Jeśli interfejs ma działać w różnych procesach, możesz utworzyć
interfejsu usługi za pomocą interfejsu
Messenger
. W ten sposób usługa określa obiektHandler
, który odpowiada na różne typy obiektówMessage
.To urządzenie (
Handler
) jest podstawą elementuMessenger
, który może następnie współdzielićIBinder
z klientem, umożliwiając mu wysyłanie poleceń do usługi za pomocą obiektówMessage
. Dodatkowo klient może zdefiniowaćMessenger
dzięki czemu usługa może wysyłać wiadomości.To najprostszy sposób komunikacji międzyprocesowej (IPC), ponieważ
Messenger
umieszcza wszystkie żądania w jednym wątku, dzięki czemu nie musisz ich projektować i zapewniać bezpieczeństwo w wątkach. - Używanie AIDL
- Android Interface Definition Language (AIDL) rozkłada obiekty na
elementów podstawowych zrozumiałych dla systemu operacyjnego i łączy je w różnych procesach, aby działać.
IPC. Poprzednia metoda, wykorzystująca
Messenger
, jest oparta na AIDL jako i jej bazowej struktury.Jak wspomnieliśmy w poprzedniej sekcji,
Messenger
tworzy kolejkę wszystkich żądań klientów w 1 wątku, więc usługa otrzymuje żądania pojedynczo. Jeśli: jednak chcesz, aby Twoja usługa obsługiwała jednocześnie wiele żądań, możesz używać AIDL bezpośrednio. W tym przypadku usługa musi być zabezpieczona wątkami i obsługiwać wiele wątków.Aby bezpośrednio korzystać z AIDL, w celu utworzenia pliku
.aidl
definiującego interfejs programowania. Narzędzia Android SDK używają aby wygenerować klasę abstrakcyjną, która implementuje interfejs i obsługuje protokół IPC, które można następnie rozszerzyć w ramach usługi.
Uwaga: w przypadku większości aplikacji AIDL nie jest najlepszym wyborem ponieważ może ona wymagać wielowątkowości oraz może być bardziej skomplikowana. Dlatego w tym dokumencie nie omówiono sposobu aby używać go w swojej usłudze. Jeśli na pewno potrzebujesz aby bezpośrednio korzystać z AIDL, zobacz AIDL dokument.
Rozszerzanie klasy Binder
Jeśli z usługi korzysta tylko aplikacja lokalna i nie musi tego robić
współdziałają z różnymi procesami,
możesz zaimplementować własną klasę Binder
, która udostępnia klientowi bezpośrednie
dostęp do publicznych metod w usłudze.
Uwaga: działa to tylko wtedy, gdy klient i usługa są w tym samym miejscu. aplikacji i procesu, co jest najczęstsze. Ta funkcja sprawdza się na przykład w przypadku muzyki musi powiązać działanie z własną usługą odtwarzającą muzykę w tle.
Ustawienia należy skonfigurować w następujący sposób:
- Utwórz w swojej usłudze instancję
Binder
, która: jedną z tych wartości:- Zawiera metody publiczne, które klient może wywołać.
- Zwraca bieżącą instancję
Service
, która ma metody publiczne który może zadzwonić. - Zwraca instancję innej klasy hostowanej przez usługę przy użyciu metod publicznych który może zadzwonić.
- Zwraca tę instancję instancji
Binder
z metody wywołania zwrotnegoonBind()
. - W kliencie odbierz
Binder
z metody wywołania zwrotnegoonServiceConnected()
oraz za pomocą podanych metod wykonywać wywołania powiązanej usługi.
Uwaga: usługa i klient muszą być w tym samym miejscu tak aby klient mógł rzutować zwrócony obiekt i prawidłowo wywoływać jego interfejsy API. Usługa i klient również muszą przejść ten sam proces, ponieważ ta metoda nie zapewnia na łączenie procesów.
Oto przykładowa usługa, która zapewnia klientom dostęp do metod w usłudze za pomocą
implementacja Binder
:
Kotlin
class LocalService : Service() { // Binder given to clients. private val binder = LocalBinder() // Random number generator. private val mGenerator = Random() /** Method for clients. */ val randomNumber: Int get() = mGenerator.nextInt(100) /** * Class used for the client Binder. Because we know this service always * runs in the same process as its clients, we don't need to deal with IPC. */ inner class LocalBinder : Binder() { // Return this instance of LocalService so clients can call public methods. fun getService(): LocalService = this@LocalService } override fun onBind(intent: Intent): IBinder { return binder } }
Java
public class LocalService extends Service { // Binder given to clients. private final IBinder binder = new LocalBinder(); // Random number generator. private final Random mGenerator = new Random(); /** * Class used for the client Binder. Because we know this service always * runs in the same process as its clients, we don't need to deal with IPC. */ public class LocalBinder extends Binder { LocalService getService() { // Return this instance of LocalService so clients can call public methods. return LocalService.this; } } @Override public IBinder onBind(Intent intent) { return binder; } /** Method for clients. */ public int getRandomNumber() { return mGenerator.nextInt(100); } }
LocalBinder
udostępnia klientom metodę getService()
pobierania:
bieżącej instancji instancji LocalService
. Umożliwia to klientom wywoływanie metod publicznych w
posprzedażna. Klienty mogą na przykład wywoływać z usługi usługę getRandomNumber()
.
Oto działanie, które wiąże z usługą LocalService
i wywołuje funkcję getRandomNumber()
po kliknięciu przycisku:
Kotlin
class BindingActivity : Activity() { private lateinit var mService: LocalService private var mBound: Boolean = false /** Defines callbacks for service binding, passed to bindService(). */ private val connection = object : ServiceConnection { override fun onServiceConnected(className: ComponentName, service: IBinder) { // We've bound to LocalService, cast the IBinder and get LocalService instance. val binder = service as LocalService.LocalBinder mService = binder.getService() mBound = true } override fun onServiceDisconnected(arg0: ComponentName) { mBound = false } } override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.main) } override fun onStart() { super.onStart() // Bind to LocalService. Intent(this, LocalService::class.java).also { intent -> bindService(intent, connection, Context.BIND_AUTO_CREATE) } } override fun onStop() { super.onStop() unbindService(connection) mBound = false } /** Called when a button is clicked (the button in the layout file attaches to * this method with the android:onClick attribute). */ fun onButtonClick(v: View) { if (mBound) { // Call a method from the LocalService. // However, if this call is something that might hang, then put this request // in a separate thread to avoid slowing down the activity performance. val num: Int = mService.randomNumber Toast.makeText(this, "number: $num", Toast.LENGTH_SHORT).show() } } }
Java
public class BindingActivity extends Activity { LocalService mService; boolean mBound = false; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); } @Override protected void onStart() { super.onStart(); // Bind to LocalService. Intent intent = new Intent(this, LocalService.class); bindService(intent, connection, Context.BIND_AUTO_CREATE); } @Override protected void onStop() { super.onStop(); unbindService(connection); mBound = false; } /** Called when a button is clicked (the button in the layout file attaches to * this method with the android:onClick attribute). */ public void onButtonClick(View v) { if (mBound) { // Call a method from the LocalService. // However, if this call is something that might hang, then put this request // in a separate thread to avoid slowing down the activity performance. int num = mService.getRandomNumber(); Toast.makeText(this, "number: " + num, Toast.LENGTH_SHORT).show(); } } /** Defines callbacks for service binding, passed to bindService(). */ private ServiceConnection connection = new ServiceConnection() { @Override public void onServiceConnected(ComponentName className, IBinder service) { // We've bound to LocalService, cast the IBinder and get LocalService instance. LocalBinder binder = (LocalBinder) service; mService = binder.getService(); mBound = true; } @Override public void onServiceDisconnected(ComponentName arg0) { mBound = false; } }; }
Poprzedni przykład pokazuje, jak klient tworzy powiązanie z usługą za pomocą implementacji
ServiceConnection
i wywołanie zwrotne onServiceConnected()
. Następny
zawiera więcej informacji o procesie tworzenia powiązania z usługą.
Uwaga: w poprzednim przykładzie para klucz-wartość
Metoda onStop()
usuwa powiązanie klienta z usługą.
Usuwanie powiązań klientów z usługami w odpowiednich momentach, jak omówiono w
Dodatkowe uwagi.
Więcej przykładowego kodu znajdziesz tutaj:
LocalService.java
i
LocalServiceActivities.java
w ApiDemos.
Korzystanie z czatu
Jeśli Twoja usługa ma komunikować się z procesami zdalnymi, możesz użyć
Messenger
udostępnia interfejs Twojej usługi. Ta technika pozwala
umożliwia korzystanie z komunikacji międzyprocesowej (IPC) bez konieczności korzystania z AIDL.
Korzystanie z interfejsu użytkownika Messenger
jest
łatwiejsze niż używanie AIDL, ponieważ kolejki: Messenger
wszystkich wywołań usługi. Interfejs czysty AIDL wysyła równocześnie żądania do
która musi obsługiwać wielowątkowość.
W większości aplikacji usługa nie musi obsługiwać wielowątkowości, więc użycie interfejsu Messenger
pozwala usłudze obsługiwać tylko 1 wywołanie w danym momencie. Jeśli to ważne
aby usługa była wielowątkowa, zdefiniuj interfejs za pomocą AIDL.
Podsumowanie korzystania z narzędzia Messenger
:
- Usługa implementuje funkcję
Handler
, która otrzymuje wywołanie zwrotne dla każdego od klienta. - Usługa używa
Handler
do utworzeniaMessenger
obiekt (który odwołuje się doHandler
). Messenger
tworzyIBinder
, które usługa wraca do klientów z:onBind()
.- Klienty używają interfejsu
IBinder
do tworzenia instancjiMessenger
(odwołuje się do polaHandler
usługi), którego klient używa do wysyłania Obiekty usługiMessage
. - Usługa odbiera każde
Message
w elemencieHandler
, a konkretnie w metodziehandleMessage()
.
Dzięki temu nie ma żadnych metod, które klient mógłby wywołać usługę. Zamiast tego makro
klient dostarcza wiadomości (obiekty: Message
), które usługa
otrzymuje w
to Handler
.
Oto prosta przykładowa usługa, która korzysta z interfejsu Messenger
:
Kotlin
/** Command to the service to display a message. */ private const val MSG_SAY_HELLO = 1 class MessengerService : Service() { /** * Target we publish for clients to send messages to IncomingHandler. */ private lateinit var mMessenger: Messenger /** * Handler of incoming messages from clients. */ internal class IncomingHandler( context: Context, private val applicationContext: Context = context.applicationContext ) : Handler() { override fun handleMessage(msg: Message) { when (msg.what) { MSG_SAY_HELLO -> Toast.makeText(applicationContext, "hello!", Toast.LENGTH_SHORT).show() else -> super.handleMessage(msg) } } } /** * When binding to the service, we return an interface to our messenger * for sending messages to the service. */ override fun onBind(intent: Intent): IBinder? { Toast.makeText(applicationContext, "binding", Toast.LENGTH_SHORT).show() mMessenger = Messenger(IncomingHandler(this)) return mMessenger.binder } }
Java
public class MessengerService extends Service { /** * Command to the service to display a message. */ static final int MSG_SAY_HELLO = 1; /** * Handler of incoming messages from clients. */ static class IncomingHandler extends Handler { private Context applicationContext; IncomingHandler(Context context) { applicationContext = context.getApplicationContext(); } @Override public void handleMessage(Message msg) { switch (msg.what) { case MSG_SAY_HELLO: Toast.makeText(applicationContext, "hello!", Toast.LENGTH_SHORT).show(); break; default: super.handleMessage(msg); } } } /** * Target we publish for clients to send messages to IncomingHandler. */ Messenger mMessenger; /** * When binding to the service, we return an interface to our messenger * for sending messages to the service. */ @Override public IBinder onBind(Intent intent) { Toast.makeText(getApplicationContext(), "binding", Toast.LENGTH_SHORT).show(); mMessenger = new Messenger(new IncomingHandler(this)); return mMessenger.getBinder(); } }
Metoda handleMessage()
w
Handler
to miejsce, w którym usługa odbiera przychodzące Message
i decyduje, co zrobić, na podstawie informacji z grupy what
.
Wystarczy, że klient utworzy Messenger
na podstawie IBinder
zwróconego przez usługę i wyśle wiadomość za pomocą send()
. Oto na przykład działanie, które wiąże się z
i dostarcza do niej komunikat MSG_SAY_HELLO
:
Kotlin
class ActivityMessenger : Activity() { /** Messenger for communicating with the service. */ private var mService: Messenger? = null /** Flag indicating whether we have called bind on the service. */ private var bound: Boolean = false /** * Class for interacting with the main interface of the service. */ private val mConnection = object : ServiceConnection { override fun onServiceConnected(className: ComponentName, service: IBinder) { // This is called when the connection with the service has been // established, giving us the object we can use to // interact with the service. We are communicating with the // service using a Messenger, so here we get a client-side // representation of that from the raw IBinder object. mService = Messenger(service) bound = true } override fun onServiceDisconnected(className: ComponentName) { // This is called when the connection with the service has been // unexpectedly disconnected—that is, its process crashed. mService = null bound = false } } fun sayHello(v: View) { if (!bound) return // Create and send a message to the service, using a supported 'what' value. val msg: Message = Message.obtain(null, MSG_SAY_HELLO, 0, 0) try { mService?.send(msg) } catch (e: RemoteException) { e.printStackTrace() } } override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.main) } override fun onStart() { super.onStart() // Bind to the service. Intent(this, MessengerService::class.java).also { intent -> bindService(intent, mConnection, Context.BIND_AUTO_CREATE) } } override fun onStop() { super.onStop() // Unbind from the service. if (bound) { unbindService(mConnection) bound = false } } }
Java
public class ActivityMessenger extends Activity { /** Messenger for communicating with the service. */ Messenger mService = null; /** Flag indicating whether we have called bind on the service. */ boolean bound; /** * Class for interacting with the main interface of the service. */ private ServiceConnection mConnection = new ServiceConnection() { public void onServiceConnected(ComponentName className, IBinder service) { // This is called when the connection with the service has been // established, giving us the object we can use to // interact with the service. We are communicating with the // service using a Messenger, so here we get a client-side // representation of that from the raw IBinder object. mService = new Messenger(service); bound = true; } public void onServiceDisconnected(ComponentName className) { // This is called when the connection with the service has been // unexpectedly disconnected—that is, its process crashed. mService = null; bound = false; } }; public void sayHello(View v) { if (!bound) return; // Create and send a message to the service, using a supported 'what' value. Message msg = Message.obtain(null, MessengerService.MSG_SAY_HELLO, 0, 0); try { mService.send(msg); } catch (RemoteException e) { e.printStackTrace(); } } @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); } @Override protected void onStart() { super.onStart(); // Bind to the service. bindService(new Intent(this, MessengerService.class), mConnection, Context.BIND_AUTO_CREATE); } @Override protected void onStop() { super.onStop(); // Unbind from the service. if (bound) { unbindService(mConnection); bound = false; } } }
Ten przykład nie pokazuje, jak usługa może odpowiedzieć klientowi.
Jeśli chcesz, aby atrybut
aby odpowiedzieć, musisz też utworzyć w kliencie Messenger
.
Gdy klient otrzyma wywołanie zwrotne onServiceConnected()
, wysyła do usługi Message
, która zawiera
Messenger
klienta w parametrze replyTo
metody send()
.
Przykład dwukierunkowej komunikacji znajdziesz w
MessengerService.java
(usługa) i
Przykłady: MessengerServiceActivities.java
(klient).
Powiąż z usługą
Komponenty aplikacji (klienci) mogą powiązać z usługą za pomocą wywołania
bindService()
Android
system następnie wywołuje metodę onBind()
usługi, która zwraca IBinder
w celu interakcji z
i z usługami.
Powiązanie jest asynchroniczne i bindService()
wraca natychmiast bez zwracania IBinder
do klienta. Aby otrzymać IBinder
, klient musi utworzyć
wystąpienia ServiceConnection
i przekazać je do bindService()
. ServiceConnection
zawiera metodę wywołania zwrotnego, która umożliwia
aby uzyskać IBinder
.
Uwaga: powiązania mogą dotyczyć tylko aktywności, usług i treści. z usługą – nie możesz utworzyć powiązania z usługą z odbiornika.
Aby utworzyć powiązanie z usługą z poziomu klienta, wykonaj te czynności:
- Wdróż
ServiceConnection
.Implementacja musi zastąpić 2 metody wywołania zwrotnego:
onServiceConnected()
- System wywołuje tę funkcję, by dostarczyć
IBinder
zwrócony przez metodyonBind()
usługi. onServiceDisconnected()
- System Android wywołuje tę funkcję, gdy połączenie z usługą jest nieoczekiwanie nawiązywane np. gdy usługa ulegnie awarii lub zostanie zatrzymana. To nie gdy funkcja usunięcie powiązania klienta.
- Wywołaj
bindService()
, przekazując implementacjęServiceConnection
.Uwaga: jeśli metoda zwraca wartość Fałsz, Klient nie ma prawidłowego połączenia z usługą. Zadzwoń jednak
unbindService()
po stronie klienta. W przeciwnym razie klient uniemożliwi usługę zamykanie, gdy jest bezczynny. - Gdy system wywoła metodę wywołania zwrotnego
onServiceConnected()
, możesz zacząć wywoływać usługę za pomocą metod określonych w interfejsie. - Aby rozłączyć się z usługą, zadzwoń pod numer
unbindService()
.Jeśli po zniszczeniu przez aplikację klient jest nadal powiązany z usługą, zniszczenie powoduje usunięcie powiązania klienta. Lepszym rozwiązaniem jest usuwanie powiązania klienta zaraz po zakończeniu tego procesu podczas interakcji z usługą. Spowoduje to wyłączenie nieaktywnej usługi. Więcej informacji na temat konfiguracji o tym, kiedy należy utworzyć powiązanie i usunąć powiązanie, zapoznaj się z sekcją Dodatkowe uwagi.
Poniższy przykład łączy klienta z usługą utworzoną wcześniej przez
rozszerzanie klasy Binder, więc wystarczy rzutować zwrócona
IBinder
do klasy LocalBinder
i poproś o instancję LocalService
:
Kotlin
var mService: LocalService val mConnection = object : ServiceConnection { // Called when the connection with the service is established. override fun onServiceConnected(className: ComponentName, service: IBinder) { // Because we have bound to an explicit // service that is running in our own process, we can // cast its IBinder to a concrete class and directly access it. val binder = service as LocalService.LocalBinder mService = binder.getService() mBound = true } // Called when the connection with the service disconnects unexpectedly. override fun onServiceDisconnected(className: ComponentName) { Log.e(TAG, "onServiceDisconnected") mBound = false } }
Java
LocalService mService; private ServiceConnection mConnection = new ServiceConnection() { // Called when the connection with the service is established. public void onServiceConnected(ComponentName className, IBinder service) { // Because we have bound to an explicit // service that is running in our own process, we can // cast its IBinder to a concrete class and directly access it. LocalBinder binder = (LocalBinder) service; mService = binder.getService(); mBound = true; } // Called when the connection with the service disconnects unexpectedly. public void onServiceDisconnected(ComponentName className) { Log.e(TAG, "onServiceDisconnected"); mBound = false; } };
Za pomocą ServiceConnection
, klient może utworzyć powiązanie z usługą
po zaliczeniu
do bindService()
, jak w tym przykładzie:
Kotlin
Intent(this, LocalService::class.java).also { intent -> bindService(intent, connection, Context.BIND_AUTO_CREATE) }
Java
Intent intent = new Intent(this, LocalService.class); bindService(intent, connection, Context.BIND_AUTO_CREATE);
- Pierwszym parametrem zmiennej
bindService()
jestIntent
wprost określa powiązanie usługi.Uwaga: jeśli zamierzasz użyć powiązania z
Service
, upewnij się, że Twoja aplikacja jest bezpieczna, używając dlatego intencji. Użycie intencji ogólnej do uruchomienia usługi zagraża bezpieczeństwu, ponieważ nie masz pewności, która usługa zareaguje na intencję, a użytkownik nie widzi, która usługa się uruchamia. Począwszy od Androida 5.0 (poziom interfejsu API 21), system zwróci wyjątek, jeśli wywołasz funkcjębindService()
z intencją niejawną. - Drugim parametrem jest obiekt
ServiceConnection
. - Trzeci parametr to flaga wskazująca opcje powiązania – zwykle
BIND_AUTO_CREATE
– służąca do utworzenia usługi, jeśli jeszcze nie jest. żyje. Inne możliwe wartości toBIND_DEBUG_UNBIND
,BIND_NOT_FOREGROUND
lub0
w przypadku braku.
Uwagi dodatkowe
Oto kilka ważnych uwag na temat powiązań z usługą:
- Zawsze przechwytuj
DeadObjectException
wyjątków, które są zgłaszane gdy połączenie zostało przerwane. Jest to jedyny wyjątek zgłoszony przez metody zdalne. - Obiekty są wartościami referencyjnymi zliczonymi w procesach.
- Powiązanie i usuwanie powiązania zazwyczaj są parowane podczas
odpowiednich momentów w cyklu życia klienta, zgodnie z opisem w
następujące przykłady:
- Jeśli chcesz korzystać z usługi tylko wtedy, gdy Twoja aktywność jest widoczna, utwórz powiązanie podczas
onStart()
i usuń powiązanie podczasonStop()
. - Jeśli chcesz, aby Twoja aktywność otrzymywała odpowiedzi nawet po zatrzymaniu jej w
w tle, utwórz powiązanie podczas
onCreate()
i usuń powiązanie w okresieonDestroy()
. Pamiętaj, że oznacza to, że działanie musi korzystać z usługi przez cały czas działania, nawet w tle, więc gdy usługa jest w innym procesie, zwiększa się waga tego procesu, że system może go zabić.
Uwaga: zazwyczaj nie tworzysz powiązań. w trakcie wywołań zwrotnych
onResume()
ionPause()
, ponieważ te wywołania mają miejsce w każdym przejścia w cyklu życia usługi. Ogranicz do minimum czas przetwarzania w tych przejściach.Ponadto, jeśli wiele działań w aplikacji jest powiązanych z tą samą usługą i istnieje przejście między może dojść do zniszczenia usługi i utworzenia jej usunięcie powiązań aktywności (podczas pauzy) przed następnym powiązaniem (podczas wznawiania). Przejście aktywności polega na czynności koordynujące swoje cykle życia zostały opisane w artykule na temat cyklu życia aktywności.
- Jeśli chcesz korzystać z usługi tylko wtedy, gdy Twoja aktywność jest widoczna, utwórz powiązanie podczas
Aby uzyskać więcej przykładowego kodu pokazującego, jak utworzyć powiązanie z usługą, zapoznaj się z
RemoteService.java
w ApiDemos.
Zarządzanie cyklem życia powiązanej usługi
Gdy usługa nie jest powiązana ze wszystkimi klientami, system Android ją zniszczy.
(chyba że była używana funkcja
startService()
).
Dzięki temu nie musisz zarządzać cyklem życia usługi,
czysto powiązana usługa. System Android zarządza nim za Ciebie na podstawie
niezależnie od tego, czy jest związana z klientami.
Jeśli jednak zdecydujesz się zaimplementować metodę wywołania zwrotnego onStartCommand()
, musisz jawnie zatrzymać usługę, ponieważ
usługa jest teraz uznawana za rozpoczętą. W takim przypadku usługa działa do momentu, gdy usługa
zatrzymuje się wywołaniem stopSelf()
lub innego komponentu stopService()
, niezależnie od tego, czy jest powiązane z
klientów.
Ponadto, jeśli usługa została uruchomiona i akceptuje wiązanie, to po wywołaniu systemu
metody onUnbind()
, możesz opcjonalnie zwrócić
true
, jeśli chcesz otrzymać połączenie z numerem onRebind()
, gdy klient następnym razem połączy się z usługą. Metoda onRebind()
zwraca nieważną wartość, ale klient nadal otrzymuje IBinder
w
onServiceConnected()
oddzwonienie.
Na ilustracji poniżej przedstawiono logikę tego rodzaju cyklu życia.
Więcej informacji o cyklu życia uruchomionej usługi znajdziesz w artykule Omówienie usług.