A Service
je aplikační komponenta, která může provádět dlouhodobé operace na pozadí. Neposkytuje uživatelské rozhraní. Jednou spuštěná služba může po určitou dobu pokračovat v běhu, a to i poté, co uživatel přepne na jinouaplikaci. Kromě toho se komponenta může vázat na službu, aby s ní mohla komunikovat, a dokonce provádět meziprocesovou komunikaci (IPC). Služba může například zpracovávat síťové transakce, přehrávat hudbu, provádět vstupy a výstupy souborů nebo komunikovat s poskytovatelem obsahu, a to vše na pozadí.
Pozor: Služba běží v hlavním vlákně svého hostitelskéhoprocesu; služba nevytváří vlastní vlákno a neběží v samostatném procesu, pokud nezadáte jinak. Veškeré blokující operace byste měli spouštět v samostatném vlákně služby, abyste se vyhnuli chybám ANR (ApplicationNot Responding).
- Typy služeb
- Výběr mezi službou a vláknem
- Základy
- Deklarování služby v manifestu
- Vytvoření spuštěné služby
- Rozšíření třídy Service
- Kotlin
- Java
- Spuštění služby
- Kotlin
- Java
- Zastavení služby
- Vytvoření vázané služby
- Posílání oznámení uživateli
- Správa životního cyklu služby
- Implementace zpětných volání životního cyklu
- Kotlin
- Java
Typy služeb
Toto jsou tři různé typy služeb:
Služba na popředí
Služba na popředí provádí nějakou operaci, která je pro uživatele viditelná. Například zvuková aplikace by použila službu popředí pro přehrávání zvukové stopy. Služby na popředí musí zobrazovat oznámení. Služby na popředí pokračují v běhu, i když uživatel s aplikací neinteraguje.
Při použití služby na popředí musíte zobrazit oznámení, aby uživatelé aktivně věděli, že služba běží. Toto oznámení nelze zrušit, pokud není služba zastavena nebo odstraněna z popředí.
Přečtěte si více o tom, jak konfigurovat služby na popředí ve vaší aplikaci.
Poznámka: Rozhraní API WorkManager nabízí flexibilní způsob plánování úloh a v případě potřeby dokáže tyto úlohy spouštět jako služby na popředí. V mnoha případech je použití WorkManageru vhodnější než přímé použití služeb na popředí.
Pozadí Služba na pozadí provádí operaci, které si uživatel přímo nevšimne. Pokud by například aplikace používala službu pro komprimaci svého úložiště, jednalo by se obvykle o službu na pozadí.
Poznámka: Pokud se vaše aplikace zaměřuje na úroveň API 26 nebo vyšší, systém ukládá omezení na spouštění služeb na pozadí, když samotná aplikace není v popředí. Ve většině situací byste například neměli přistupovat k informacím o poloze z pozadí. Místo toho naplánujte úlohy pomocí nástroje WorkManager.
Vázaná Služba je vázaná, když se k ní komponenta aplikace váže volánímbindService()
. Vázaná služba nabízí rozhraní klient-server, které umožňuje komponentám komunikovat se službou, posílat požadavky, přijímat výsledky, a to i napříč procesy pomocí meziprocesové komunikace (IPC). Vázaná služba běží pouze tak dlouho, dokud je k ní vázána jiná komponenta aplikace. Ke službě se může vázat více komponent najednou, ale jakmile se všechny odvážou, služba se zničí.
Ačkoli tato dokumentace obecně pojednává o spuštěných a vázaných službách odděleně,vaše služba může fungovat oběma způsoby – může být spuštěná (běžet neomezeně dlouho) a také umožňovat vázání. Je to jednoduše otázka toho, zda implementujete několik metod zpětného volání: onStartCommand()
, abyste umožnili komponentám její spuštění, a onBind()
, abyste umožnili vázání.
Nezávisle na tom, zda je vaše služba spuštěná, vázaná nebo obojí, může jakákoli komponenta aplikace používat službu (i ze samostatné aplikace) stejným způsobem, jakým může jakákoli komponenta používat aktivitu – jejím spuštěním pomocí Intent
. Službu však můžete v souboru manifestu deklarovat jako soukromou a zablokovat k ní přístup z jiných aplikací.Více o tom pojednává část Deklarování služby v manifestu.
Výběr mezi službou a vláknem
Služba je jednoduše komponenta, která může běžet na pozadí, i když uživatel neinteraguje s vaší aplikací, takže službu byste měli vytvořit pouze v případě, že ji potřebujete.
Pokud musíte provádět práci mimo hlavní vlákno, ale pouze v době, kdy uživatel interaguje s vaší aplikací, měli byste místo toho vytvořit nové vlákno v kontextu jiné komponenty aplikace. Pokud například chcete přehrát nějakou hudbu, ale pouze v době, kdy je vaše aktivita spuštěna, můžete vytvořit vlákno v onCreate()
, spustit ho v onStart()
a zastavit v onStop()
. zvažte také použití poolu vláken a exekutorů z balíčku java.util.concurrent
nebo koroutin Kotlin místo tradiční třídyThread
. Další informace o přesunu provádění do vláken na pozadí naleznete v dokumentuThreading on Android.
Pamatujte, že pokud používáte službu, stále běží ve výchozím nastavení v hlavním vlákně aplikace, takže byste měli v rámci služby vytvořit nové vlákno, pokud provádí intenzivní nebo blokující operace.
Základy
Chcete-li vytvořit službu, musíte vytvořit podtřídu Service
nebo použít některou z jejích existujících podtříd. Ve své implementaci musíte přepsat některé metody zpětného volání, které obsluhují klíčové aspekty životního cyklu služby, a poskytnout mechanismus, který případně umožní komponentám navázat se na službu. Toto jsou nejdůležitější metody zpětného volání, které byste měli přepsat:
onStartCommand()
Systém vyvolá tuto metodu volánímstartService()
, když jiná komponenta (například aktivita) požádá o spuštění služby. když se tato metoda provede, služba je spuštěna a může běžet na pozadí po neomezenou dobu. Pokud tuto metodu implementujete, je vaší odpovědností službu po dokončení její práce zastavit voláním
stopSelf()
nebostopService()
. Pokud chcete pouze zajistit vazbu, nemusíte tuto metodu implementovat.onBind()
Systém vyvolá tuto metodu volánímbindService()
, když se jiná komponenta chce se službou svázat (například provést RPC). ve své implementaci této metody musíte poskytnout rozhraní, které klientipoužívají ke komunikaci se službou vrácenímIBinder
. Tuto metodu musíte vždyimplementovat; pokud však nechcete povolit vazbu, měli byste vrátitnull.onCreate()
Systém vyvolá tuto metodu, aby provedl jednorázové nastavovací procedury při počátečním vytvoření služby (předtím, než zavolá buďonStartCommand()
neboonBind()
). Pokud je služba již spuštěna, tato metoda se nevyvolává.onDestroy()
Systém vyvolá tuto metodu, když služba již není používána a je zničena. vaše služba by ji měla implementovat, aby vyčistila všechny zdroje, jako jsou vlákna, registrované posluchače nebo přijímače. Toto je poslední volání, které služba obdrží.
Pokud komponenta spustí službu voláním startService()
(což má za následek volání onStartCommand()
), službapokračuje v běhu, dokud se sama nezastaví voláním stopSelf()
nebo dokud ji jiná komponenta nezastaví voláním stopService()
.
Pokud komponenta zavolábindService()
pro vytvoření služby a onStartCommand()
není volána, služba poběží tak dlouho, dokud je k ní komponenta vázána. Poté, co je služba odvázána od všech svých klientů,systém ji zničí.
Systém Android zastaví službu pouze tehdy, když je málo paměti a musí obnovit systémové zdroje pro činnost, na kterou se uživatel zaměřil. Pokud je služba vázána na aktivitu, která má zaměření uživatele, je méně pravděpodobné, že bude zničena; pokud je služba deklarována jako běžící v popředí, je zřídkakdy zničena. pokud je služba spuštěna a běží dlouho, systém postupem času snižuje její pozici v seznamu úloh na pozadí a služba se stává velmi náchylnou na zničení – pokud je vaše služba spuštěna, musíte ji navrhnout tak, aby se s restarty ze strany systému vyrovnala elegantně. Pokud systém vaši službu zabije, znovu ji spustí, jakmile budou k dispozici zdroje, ale to také závisí na hodnotě, kterou vrátíte z onStartCommand()
. Další informace o tom, kdy může systém službu zničit, najdete v dokumentu Processes and Threading.
V následujících částech uvidíte, jak můžete vytvořit metodystartService()
abindService()
služby a jak je používat z jiných aplikačních komponent.
Deklarování služby v manifestu
Všechny služby musíte deklarovat v souboru manifestu vaší aplikace, stejně jako to děláte u aktivit a dalších komponent.
Pro deklarování služby přidejte element <service>
jako potomka elementu <application>
. Zde je příklad:
<manifest ... > ... <application ... > <service android:name=".ExampleService" /> ... </application></manifest>
Podívejte se na odkaz na prvek <service>
, kde najdete další informace o deklarování služby v manifestu.
Existují další atributy, které můžete zahrnout do prvku <service>
pro definování vlastností, jako jsou oprávnění, která jsou vyžadována pro spuštění služby, a proces, ve kterém má služba běžet. Atribut android:name
je jediným povinným atributem – určuje název třídy služby. Po zveřejnění aplikace ponechte tento název beze změny, abyste se vyhnuli riziku rozbití kódu kvůli závislosti na explicitních záměrech pro spuštění nebo svázání služby (přečtěte si příspěvek na blogu ThingsThat Cannot Change).
Pozor: Abyste zajistili bezpečnost své aplikace, vždy používejte při spouštění Service
explicitní záměr a nedeklarujte pro své služby filtry záměrů. Použití implicitního záměru pro spuštění služby představuje bezpečnostní riziko, protože si nemůžete být jisti, která služba na záměr odpoví, a uživatel nevidí, která služba se spustí. Počínaje systémem Android 5.0 (úroveň API 21) systém vyhodí výjimku, pokud zavolátebindService()
s implicitním záměrem.
Můžete zajistit, že vaše služba bude dostupná pouze pro vaši aplikaci tím, že zahrnete atribut android:exported
a nastavíte jej na false
. Tím účinně zabráníte ostatním aplikacím ve spuštění vaší služby, a to i při použití explicitního záměru.
Poznámka: Uživatelé mohou vidět, jaké služby jsou na jejich zařízení spuštěny. Pokud uvidí službu, kterou nepoznávají nebo které nedůvěřují, mohou ji zastavit. Aby se uživatelé vyhnuli náhodnému zastavení služby, je třeba přidat atribut android:description
do prvku <service>
v manifestu aplikace. V popisu uveďte krátkou větu vysvětlující, co služba dělá a jaké výhody poskytuje.
Vytvoření spuštěné služby
Spuštěná služba je taková, kterou jiná komponenta spustí voláním startService()
, což vede k volání metodyonStartCommand()
služby.
Když je služba spuštěna, má životní cyklus nezávislý na komponentě, která ji spustila. Služba může běžet na pozadí neomezeně dlouho, i když je komponenta, která ji spustila, zničena. Služba jako taková by se měla zastavit, když je její práce dokončena, voláním stopSelf()
, nebo ji může zastavit jiná komponenta voláním stopService()
.
Aplikační komponenta, například aktivita, může službu spustit voláním startService()
a předáním Intent
, který specifikuje službu a obsahuje veškerá data, která má služba použít. Služba obdrží tento Intent
v metodě onStartCommand()
.
Předpokládejme například, že aktivita potřebuje uložit nějaká data do online databáze. Aktivitamůže spustit doprovodnou službu a předat jí data k uložení předáním záměru startService()
. Služba přijme záměr v onStartCommand()
, připojí se k internetu a provede transakci s databází. Po dokončení transakce se služba sama zastaví a jezničena.
Pozor: Služba běží ve stejném procesu jako aplikace, ve které je deklarována, a ve výchozím nastavení v hlavním vlákně této aplikace. Pokud vaše službaprovádí intenzivní nebo blokující operace, zatímco uživatel interaguje s aktivitou ze stejnéaplikace, služba zpomaluje výkon aktivity. Chcete-li se vyhnout ovlivnění výkonu aplikace, spusťte uvnitř služby nové vlákno.
Třída Service
je základní třídou pro všechny služby. Když tuto třídu rozšiřujete, je důležité vytvořit nové vlákno, ve kterém může služba dokončit veškerou svou práci; služba ve výchozím nastavení používá hlavní vlákno vaší aplikace, což může zpomalit výkon jakékoli aktivity, která je spuštěna vaší aplikací.
Frame framework Android také poskytuje podtřídu IntentService
Service
, která používá pracovní vlákno pro zpracování všech požadavků na spuštění, a to po jednom. Použití této třídy se nedoporučuje pro nové aplikace, protože nebude dobře fungovat počínaje Androidem 8 Oreo kvůlizavedení limitů pro provádění na pozadí. navíc je zastaralá počínaje Androidem 11. Jako náhradu za IntentService
můžete použít JobIntentService, která je kompatibilní s novějšími verzemi Androidu.
Následující části popisují, jak můžete implementovat vlastní službu, nicméně pro většinu případů použití byste měli důrazně zvážit použití WorkManageru. Podívejte se do průvodce zpracováním na pozadí v systému Android, zda existuje řešení, které vyhovuje vašim potřebám.
Rozšíření třídy Service
Třídu Service
můžete rozšířit tak, aby zpracovávala každý příchozí záměr. Takto může vypadat základní implementace:
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(); }}
Ukázkový kód zpracovává všechna příchozí volání v onStartCommand()
a odesílá práci do Handler
běžícího na pozadí vlákna. Funguje stejně jako IntentService
a zpracovává všechny požadavky sériově, jeden po druhém.
Poznamenejte, že metoda onStartCommand()
musí vracet celé číslo.
Můžete kód změnit tak, aby práce probíhala například na poolu vláken, pokud chcete spouštět více požadavků současně. Celé číslo je hodnota, která popisuje, jak má systém pokračovat ve službě v případě, že ji systém zabije. Návratováhodnotazmetody onStartCommand()
musí být jedna z následujícíchkonstant:
START_NOT_STICKY
Pokud systém službu zabije po návratu metodyonStartCommand()
, nevytvářejte službu znovu, pokud nejsou nevyřízenéintence k doručení. Toto je nejbezpečnější možnost, jak se vyhnout spuštění služby, když to není nutnéa když vaše aplikace může jednoduše restartovat všechny nedokončené úlohy.START_STICKY
Pokud systém službu po návratuonStartCommand()
ukončí, službu znovu vytvořte a zavolejteonStartCommand()
, ale poslední záměr znovu nedoručujte. místo toho systém zavoláonStartCommand()
s nulovým záměrem, pokud neexistují čekající záměry na spuštění služby. V takovém případě jsou tyto záměry doručeny. To je vhodné pro přehrávače médií (nebo podobné služby), které neprovádějípříkazy, ale jsou spuštěny na dobu neurčitou a čekají na úlohu.START_REDELIVER_INTENT
Pokud systém službu po návratuonStartCommand()
ukončí, vytvořte službu znovu a zavolejteonStartCommand()
s posledním záměrem, který byl službě doručen. Všechny čekající záměry jsou doručeny postupně. To je vhodné pro služby, které aktivně provádějí úlohu, která by měla být okamžitě obnovena, například stahování souboru.
Další podrobnosti o těchto návratových hodnotách najdete v odkazované dokumentaci ke každé konstantě.
Spuštění služby
Službu můžete spustit z aktivity nebo jiné komponenty aplikace předáním Intent
konstantě startService()
nebo startForegroundService()
. Systém Android zavolá metodu onStartCommand()
služby a předá jí Intent
, která určuje, která služba se má spustit.
Poznámka: Pokud se vaše aplikace zaměřuje na úroveň API 26 nebo vyšší, systém ukládá omezení na používání nebo vytváření služeb na pozadí, pokud není samotná aplikace v popředí. Pokud aplikace potřebuje vytvořit službu na popředí, měla by zavolat startForegroundService()
. Touto metodou se vytvoří služba na pozadí, ale metoda signalizuje systému, že se služba povýší do popředí. Po vytvoření služby musí služba do pěti sekund zavolat svou metodu startForeground()
.
Příklad aktivita může spustit příklad služby z předchozí části (HelloService
) pomocí explicitního záměru s startService()
, jak je uvedeno zde:
Kotlin
Intent(this, HelloService::class.java).also { intent -> startService(intent)}
Java
Intent intent = new Intent(this, HelloService.class);startService(intent);
Metoda startService()
se okamžitě vrátí a systém Android zavolá metodu onStartCommand()
služby. Pokud služba ještě neběží, systém nejprve zavolá metodu onCreate()
a poté zavolá metoduonStartCommand()
.
Pokud služba neposkytuje také vazbu, je záměr, který je doručen pomocí startService()
, jediným způsobem komunikace mezi aplikační komponentou a službou. Pokud však chcete, aby služba odeslala výsledek zpět,může klient, který službu spouští, vytvořit PendingIntent
pro vysílání (pomocí getBroadcast()
) a doručit jej službě v Intent
, která službu spouští. Služba pak může tento broadcast použít k doručení výsledku.
Vícenásobné požadavky na spuštění služby vedou k vícenásobnému odpovídajícímu volání službyonStartCommand()
. K zastavení služby je však zapotřebí pouze jeden požadavek na její zastavení (pomocí stopSelf()
nebo stopService()
).
Zastavení služby
Spuštěná služba musí řídit svůj vlastní životní cyklus. To znamená, že systém službu nezastaví, aby ji zničil, pokud nemusí obnovit systémovou paměť a službapokračuje v běhu po návratu onStartCommand()
. Služba se musí zastavit sama voláním stopSelf()
, nebo ji může zastavit jiná komponenta voláním stopService()
.
Jakmile je požadováno zastavení pomocí stopSelf()
nebo stopService()
, systém službu co nejdříve zničí.
Pokud vaše služba zpracovává více požadavků na onStartCommand()
současně, neměli byste službu zastavovat po dokončení zpracování požadavku na spuštění, protože byste mohli obdržet nový požadavek na spuštění (zastavení na konci prvního požadavku by ukončilo druhý). Chcete-li se tomuto problému vyhnout, můžete použít stopSelf(int)
, abyste zajistili, že váš požadavek na zastavení služby bude vždy založen na posledním požadavku na spuštění. To znamená, že při volání stopSelf(int)
předáte ID požadavku na spuštění (startId
doručený onStartCommand()
), na který váš požadavek na zastavení odpovídá. Pokud pak služba obdrží nový požadavek na spuštění dříve, než stihnete zavolat stopSelf(int)
, ID se neshoduje a služba se nezastaví.
Upozornění: Aby nedocházelo k plýtvání systémovými prostředky a spotřebovávání energie z baterie, zajistěte, aby vaše aplikace po ukončení práce zastavila své služby. v případě potřeby mohou ostatní komponenty službu zastavit voláním stopService()
. I když pro službu povolíte vazbu,musíte službu vždy sami zastavit, pokud někdy obdrží volání onStartCommand()
.
Další informace o životním cyklu služby naleznete v následující části Správa životního cyklu služby.
Vytvoření vázané služby
Vázaná služba je taková služba, která umožňuje aplikačním komponentám, aby se k ní vázaly voláním bindService()
pro vytvoření dlouhodobého spojení.Obecně neumožňuje komponentám spustit ji voláním startService()
.
Vázanou službu vytvoříte, pokud chcete se službou komunikovat z aktivit a jiných komponent v aplikaci nebo chcete vystavit některé funkce aplikace jiným aplikacím prostřednictvím meziprocesové komunikace (IPC).
Pro vytvoření vázané služby implementujte metodu zpětného volání onBind()
, která vrátí IBinder
definující rozhraní pro komunikaci se službou. Ostatní komponenty aplikace pak mohou volánímbindService()
načíst rozhraní azačít volat metody služby. Služba žije pouze proto, aby sloužila aplikační komponentě, která je k ní vázána, takže když ke službě není vázána žádná komponenta, systém ji zničí. vázanou službu nemusíte zastavit stejným způsobem, jako když je služba spuštěna prostřednictvím onStartCommand()
.
Pro vytvoření vázané služby musíte definovat rozhraní, které určuje, jak může klient se službou komunikovat. Toto rozhraní mezi služboua klientem musí být implementací IBinder
a je tím, co musí vaše službavrátit z metody zpětného volání onBind()
. Poté, co klient obdrží rozhraní IBinder
, může začítinterakci se službou prostřednictvím tohoto rozhraní.
Ke službě se může vázat více klientů současně. Když klient ukončí interakci se službou, zavolá unbindService()
pro zrušení vazby.
Pokud nejsou ke službě vázáni žádní klienti, systém službu zničí.
Existuje více způsobů, jak implementovat vázanou službu, a implementace je složitější než u spuštěné služby. Z těchto důvodů se pojednání o vázaných službách objevuje v samostatném dokumentu o vázaných službách.
Posílání oznámení uživateli
Když je služba spuštěna, může uživatele informovat o událostech pomocí oznámení toastu nebo oznámení stavového řádku.
Oznámení toastu je zpráva, která se objeví na povrchu aktuálního okna pouze na okamžik a poté zmizí. Oznámení na stavovém řádku poskytuje ikonu na stavovém řádku se zprávou, kterou může uživatel vybrat, aby provedl nějakou akci (například spustil nějakou činnost).
Obvykle je oznámení na stavovém řádku nejlepší technikou, kterou lze použít, pokud byla dokončena práce na pozadí, například stahování souborů, a uživatel s ní nyní může něco dělat. Když uživatel vybere oznámení z rozšířeného zobrazení, může oznámení spustit činnost (například zobrazit stažený soubor).
Další informace najdete v příručkách pro vývojáře Toast Notifications nebo Status Bar Notifications.
Správa životního cyklu služby
Životní cyklus služby je mnohem jednodušší než životní cyklus činnosti. Je však ještě důležitější, abyste věnovali velkou pozornost tomu, jak je vaše služba vytvořena a zničena, protože služba může běžet na pozadí, aniž by o tom uživatel věděl.
Životní cyklus služby – od okamžiku jejího vytvoření až po její zničení – může probíhat jednou z těchto dvou cest:
- Spuštěná služba
Služba je vytvořena, když jiná komponenta zavolá
startService()
. Služba pak běží neomezeně dlouho a musí se zastavit volánímstopSelf()
. Jiná komponenta může službu také zastavit volánímstopService()
. Když je služba zastavena, systém ji zničí. - Vázaná služba
Služba je vytvořena, když jiná komponenta (klient) zavolá
bindService()
. Klient pak komunikuje se službouprostřednictvím rozhraníIBinder
. Klient může spojení uzavřít volánímunbindService()
. Ke stejné službě se může vázat více klientů, a když se všichni odvážou, systém službu zruší. Službase nemusí sama zastavit.
Tyto dvě cesty nejsou zcela oddělené. Pomocí startService()
můžete navázat službu, která je již spuštěna. Například můžete spustit hudební službu na pozadí tak, že zavoláte startService()
s Intent
, který identifikuje hudbu, která se má přehrát. Později,případně až bude chtít uživatel vykonávat nějakou kontrolu nad přehrávačem nebo získat informace o aktuální skladbě, může se aktivita vázat na službu voláním bindService()
. V takových případech stopService()
nebo stopSelf()
ve skutečnosti službu nezastaví, dokud se všichni klienti nerozvážou.
Implementace zpětných volání životního cyklu
Stejně jako aktivita má i služba metody zpětného volání životního cyklu, které můžete implementovat pro sledovánízměn stavu služby a provádění práce ve vhodnou dobu. Následující kostra služby demonstruje každou z metod životního cyklu:
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 () { // The service is being created } override fun (intent: Intent?, flags: Int, startId: Int): Int { // The service is starting, due to a call to startService() return startMode } override fun (intent: Intent): IBinder? { // A client is binding to the service with bindService() return binder } override fun (intent: Intent): Boolean { // All clients have unbound with unbindService() return allowRebind } override fun (intent: Intent) { // A client is binding to the service with bindService(), // after onUnbind() has already been called } override fun () { // 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 () { // The service is being created } @Override public int (Intent intent, int flags, int startId) { // The service is starting, due to a call to return startMode; } @Override public IBinder (Intent intent) { // A client is binding to the service with return binder; } @Override public boolean (Intent intent) { // All clients have unbound with return allowRebind; } @Override public void (Intent intent) { // A client is binding to the service with , // after onUnbind() has already been called } @Override public void () { // The service is no longer used and is being destroyed }}
Poznámka: Na rozdíl od metod zpětného volání životního cyklu aktivity nemusíte volat implementaci těchto metod zpětného volání nadtřídy.
Obrázek 2. Metody zpětného volání životního cyklu služby. Životní cyklus služby. Diagram vlevo ukazuje životní cyklus, když je služba vytvořena pomocí startService()
, a diagram vpravo ukazuje životní cyklus, když je služba vytvořena pomocí bindService()
.
Obrázek 2 znázorňuje typické metody zpětného volání služby. Ačkoli obrázek odděluje služby vytvořené pomocí startService()
od služeb vytvořených pomocí bindService()
, mějte na paměti, že každá služba, bez ohledu na to, jak je spuštěna, může potenciálně umožnit klientům, aby se na ni vázali. služba, která byla původně spuštěna pomocí onStartCommand()
(klientem volajícím startService()
)může stále přijímat volání onBind()
(když klient volábindService()
).
Implementací těchto metod můžete sledovat tyto dvě vnořené smyčky životního cyklu služby:
- Celá životnost služby probíhá mezi okamžikem volání
onCreate()
a okamžikem návratuonDestroy()
. Stejně jako aktivita provede služba své počáteční nastavení vonCreate()
a uvolní všechny zbývající zdroje vonDestroy()
. Například služba přehrávání hudby může vytvořit vlákno, ve kterém se přehrává hudba, vonCreate()
, a pak může toto vlákno ukončit vonDestroy()
.Poznámka: Metody
onCreate()
aonDestroy()
jsou volány pro všechny služby, ať už jsou vytvořeny pomocístartService()
nebobindService()
. - Aktivní životnost služby začíná voláním
onStartCommand()
neboonBind()
. každé metodě je předánIntent
, který byl předán buďstartService()
, nebobindService()
.Pokud je služba spuštěna, aktivní životnost končí ve stejném okamžiku, kdy končí celá životnost (služba je stále aktivní i po návratu
onStartCommand()
). Pokud je služba vázaná, aktivní životnost končí v okamžiku, kdy se vrátíonUnbind()
.
Poznámka: Přestože je spuštěná služba zastavena voláním buď stopSelf()
, nebo stopService()
, neexistuje pro ni příslušné zpětné volání (neexistuje zpětné volání onStop()
). Pokud není služba vázána na klienta, systém ji při zastavení zničí – onDestroy()
je jediným přijatým zpětným voláním.
Další informace o vytváření služby, která poskytuje vazbu, naleznete v dokumentu Vázané služby, který obsahuje další informace o metodě onRebind()
zpětného volání v části o Správě životního cyklu vázané služby.
.