Een Service
is een applicatie component dat langdurig draaiende operaties op de achtergrond kan uitvoeren. Het biedt geen gebruikersinterface. Eenmaal op de achtergrond kan een service nog enige tijd blijven draaien, zelfs nadat de gebruiker naar een andere applicatie is overgeschakeld. Bovendien kan een component zich aan een service binden om ermee te interageren en zelfs om interprocesscommunicatie (IPC) uit te voeren. Een service kan bijvoorbeeld netwerktransacties afhandelen, muziek afspelen, bestands-I/O uitvoeren, of communiceren met een content provider, allemaal vanuit de achtergrond.
Voorzichtigheid: Een service draait in de hoofdthread van zijn hostingproces; de service maakt geen eigen thread aan en draait niet in een apart proces, tenzij u anders aangeeft. U moet alle blokkeringsoperaties op een aparte thread binnen de service uitvoeren om ApplicationNot-Response (ANR) fouten te voorkomen.
- Types van services
- Kiezen tussen een service en een thread
- De basis
- Een service declareren in het manifest
- Een gestarte service maken
- Uitbreiding van de Service klasse
- Kotlin
- Java
- Start een service
- Kotlin
- Java
- Stoppen van een service
- Een gebonden service maken
- Meldingen naar de gebruiker sturen
- Het beheren van de levenscyclus van een service
- Implementeren van de lifecycle callbacks
- Kotlin
- Java
Types van services
Dit zijn de drie verschillende types van services:
Voorgrond
Een voorgrond service voert een of andere operatie uit die merkbaar is voor de gebruiker. Bijvoorbeeld, een audio app zou een voorgrond dienst gebruiken om een audio track af te spelen. Voorgronddiensten moeten een Melding tonen. Voorgronddiensten blijven draaien, zelfs wanneer de gebruiker geen interactie heeft met de app.
Wanneer u een voorgronddienst gebruikt, moet u een melding weergeven, zodat gebruikers actief op de hoogte zijn dat de dienst draait. Deze melding kan niet worden verwijderd, tenzij de service wordt gestopt of van de voorgrond wordt verwijderd.
Lees meer over hoe u voorgronddiensten in uw app kunt configureren.
Opmerking: De WorkManager API biedt een flexibele manier om taken te plannen, en kan deze taken indien nodig als voorgronddiensten uitvoeren. In veel gevallen is het gebruik van WorkManager te verkiezen boven het directe gebruik van voorgronddiensten.
Achtergrond Een achtergrond service voert een operatie uit die niet direct wordt opgemerkt door de gebruiker. Bijvoorbeeld, als een app een service gebruikt om de opslagruimte te verkleinen, dan is dat meestal een achtergrond service.
Opmerking: Als uw app API-niveau 26 of hoger heeft, legt het systeem beperkingen op voor het uitvoeren van achtergronddiensten wanneer de app zelf niet op de voorgrond staat. In de meeste situaties moet u bijvoorbeeld geen locatie-informatie opvragen vanuit de achtergrond. Plan in plaats daarvan taken met WorkManager.
Gebonden Een service is gebonden wanneer een applicatiecomponent eraan bindt door
bindService()
aan te roepen. Een gebonden service biedt een client-server-interface waarmee componenten kunnen communiceren met de service, verzoeken kunnen verzenden, resultaten kunnen ontvangen en dit zelfs over processen heen kunnen doen met interprocesscommunicatie (IPC). Een gebonden service draait alleen zolang een andere applicatiecomponent eraan gebonden is. Meerdere componenten kunnen zich tegelijk aan de service binden, maar als ze zich allemaal ontkoppelen, wordt de service vernietigd.
Hoewel deze documentatie over het algemeen afzonderlijk ingeschakelde en gebonden services bespreekt, kan uw service op beide manieren werken – hij kan worden opgestart (om voor onbepaalde tijd te draaien) en ook gebondenheid toestaan. Het is gewoon een kwestie van of je een paar callback methodes implementeert: onStartCommand()
om componenten in staat te stellen de service te starten en onBind()
om binding toe te staan.
Of uw service nu is gestart, gebonden, of beide, elke applicatiecomponent kan de service gebruiken (zelfs vanuit een aparte applicatie) op dezelfde manier als elke component een activiteit kan gebruiken door deze te starten met een Intent
. U kunt de service echter als privé declareren in het manifest-bestand en de toegang van andere applicaties blokkeren.Dit wordt meer besproken in het gedeelte over Declaring the service in themanifest.
Kiezen tussen een service en een thread
Een service is eenvoudigweg een component die op de achtergrond kan draaien, zelfs wanneer de gebruiker geen interactie heeft met uw applicatie, dus u zou alleen een service moeten maken als dat is wat u nodig hebt.
Als u werk moet uitvoeren buiten uw hoofdthread, maar alleen terwijl de gebruiker interactie heeft met uw toepassing, moet u in plaats daarvan een nieuwe thread maken in de context van een andere toepassingscomponent. Bijvoorbeeld, als u wat muziek wilt afspelen, maar alleen terwijl uw activiteit loopt, zou u een thread kunnen maken in onCreate()
, beginnen met draaien in onStart()
, en stoppen in onStop()
.Overweeg ook het gebruik van thread pools en executors uit het java.util.concurrent
pakket of Kotlin coroutines in plaats van de traditioneleThread
klasse. Zie hetThreading on Android document voor meer informatie over het verplaatsen van de uitvoering naar achtergrond threads.
Bedenk dat als u een service gebruikt, deze nog steeds standaard in de hoofdthread van uw applicatie draait, dus u moet nog steeds een nieuwe thread binnen de service maken als deze intensieve of blokkerende bewerkingen uitvoert.
De basis
Om een service te maken, moet u een subclass van Service
maken of een van de bestaande subclasses gebruiken. In uw implementatie moet u enkele callback-methoden overschrijven die belangrijke aspecten van de levenscyclus van de service afhandelen en een mechanisme verschaffen waarmee de componenten aan de service kunnen worden gekoppeld, indien van toepassing. Dit zijn de belangrijkste callback methoden die u zou moeten overriden:
onStartCommand()
Het systeem roept deze methode aan doorstartService()
aan te roepen wanneer een ander component (zoals een activiteit) verzoekt om de service te starten.Wanneer deze methode wordt uitgevoerd, wordt de service gestart en kan deze voor onbepaalde tijd op de achtergrond draaien. Als u dit implementeert, is het uw verantwoordelijkheid om de service te stoppen wanneer het werk is voltooid doorstopSelf()
ofstopService()
aan te roepen. Als u alleen binding wilt aanbieden, hoeft u deze methode niet te implementeren.onBind()
Het systeem roept deze methode op doorbindService()
aan te roepen wanneer een ander component met de service wil binden (zoals om RPC uit te voeren).In uw implementatie van deze methode moet u een interface verschaffen die clients gebruiken om met de service te communiceren door eenIBinder
terug te sturen. U moet deze methode altijd implementeren; als u echter geen binding wilt toestaan, moet uIBinder
teruggeven.onCreate()
Het systeem roept deze methode aan om eenmalige setup-procedures uit te voeren wanneer de service voor het eerst wordt aangemaakt (voordat hetonStartCommand()
ofonBind()
aanroept). Als de dienst al loopt, wordt deze methode niet aangeroepen.onDestroy()
Het systeem roept deze methode aan wanneer de service niet langer wordt gebruikt en wordt vernietigd. Uw service moet dit implementeren om resources zoals threads, registeredlisteners, of ontvangers op te ruimen. Dit is de laatste aanroep die de service ontvangt.
Als een component de service start door startService()
aan te roepen (wat resulteert in een oproep aan onStartCommand()
), blijft de service draaien totdat deze zichzelf stopt met stopSelf()
of een andere component deze stopt door stopService()
aan te roepen.
Als een componentbindService()
aanroept om de service te maken en onStartCommand()
niet wordt aangeroepen, blijft de service draaien zolang de component eraan is gebonden. Nadat de service is ontkoppeld van al zijn clients, vernietigt het systeem deze.
Het Android-systeem stopt een service alleen wanneer het geheugen bijna leeg is en het systeembronnen moet herstellen voor de activiteit die de gebruikersfocus heeft. Als de service is gekoppeld aan een activiteit die de gebruikersfocus heeft, is het minder waarschijnlijk dat deze wordt gedood; als de service is gedeclareerd om op de voorgrond te draaien, wordt deze zelden gedood.Als de service wordt gestart en lang wordt uitgevoerd, verlaagt het systeem zijn positie in de lijst met achtergrondtaken na verloop van tijd en wordt de service zeer gevoelig voor het stoppen ervan-als uw service wordt gestart, moet u deze zo ontwerpen dat deze netjes omgaat met herstarts door het systeem. Als het systeem uw dienst doodt, start het de dienst opnieuw op zodra er middelen beschikbaar komen, maar dit hangt ook af van de waarde die u teruggeeft met onStartCommand()
. Voor meer informatie over wanneer het systeem een service zou kunnen vernietigen, zie het Processes and Threading document.
In de volgende secties ziet u hoe u destartService()
enbindService()
service methodes kunt maken, en ook hoe u ze kunt gebruiken vanuit andere applicatie componenten.
Een service declareren in het manifest
U moet alle services declareren in het manifest-bestand van uw applicatie, net zoals u dat doet voor activiteiten en andere componenten.
Om uw service te declareren, voegt u een <service>
-element toe als een child van het <application>
-element. Hier is een voorbeeld:
<manifest ... > ... <application ... > <service android:name=".ExampleService" /> ... </application></manifest>
Zie de <service>
element referentie voor meer informatie over het declareren van uw service in het manifest.
Er zijn andere attributen die u kunt opnemen in het <service>
element om eigenschappen te definiëren, zoals de permissies die nodig zijn om de service te starten en het proces waarin de service moet draaien. Het android:name
-attribuut is het enige vereiste attribuut: het specificeert de classnaam van de service. Laat deze naam ongewijzigd nadat u uw toepassing hebt gepubliceerd om het risico van breukcode te vermijden als gevolg van afhankelijkheid van expliciete intenties om de service te starten of te binden (lees de blogpost, ThingsThat Cannot Change).
Voorzichtigheid: Om ervoor te zorgen dat uw app veilig is, gebruikt u altijd eenexpliciete intentie bij het starten van een Service
en declareert u geen intentiefilters vooruw services. Het gebruik van een impliciete intentie om een service te starten is een veiligheidsrisico omdat u niet zeker kunt zijn van de service die op de intentie reageert, en de gebruiker niet kan zien welke service wordt gestart. Beginnend met Android 5.0 (API-niveau 21), gooit het systeem een uitzondering als ubindService()
aanroept met een impliciete intentie.
U kunt ervoor zorgen dat uw service alleen beschikbaar is voor uw app door het android:exported
-attribuut op te nemen en het in te stellen op false
. Dit voorkomt effectief dat andere apps uw service kunnen starten, zelfs wanneer u een expliciete intentie gebruikt.
Note: Gebruikers kunnen zien welke services op hun apparaat worden uitgevoerd. Als ze een service zien die ze niet herkennen of vertrouwen, kunnen ze de service stoppen. Om te voorkomen dat uw service per ongeluk wordt gestopt door gebruikers, moet u het android:description
-attribuut toevoegen aan het <service>
-element in uw app manifest. Geef in de beschrijving een korte zin waarin wordt uitgelegd wat de service doet en welke voordelen deze biedt.
Een gestarte service maken
Een gestarte service is er een die een andere component start door startService()
aan te roepen, wat resulteert in een aanroep van de methodeonStartCommand()
van de service.
Wanneer een service is gestart, heeft deze een levenscyclus die onafhankelijk is van de component die hem heeft gestart. De service kan voor onbepaalde tijd op de achtergrond draaien, zelfs als de component die hem heeft gestart wordt vernietigd. Als zodanig moet de service zichzelf stoppen wanneer zijn taak is voltooid door stopSelf()
te roepen, of een andere component kan hem stoppen door stopService()
te roepen.
Een toepassingscomponent zoals een activiteit kan de service starten door startService()
te roepen en een Intent
door te geven die de service specificeert en alle gegevens bevat die de service moet gebruiken. De dienst ontvangt deze Intent
in de methode onStartCommand()
.
Voor stel bijvoorbeeld dat een activiteit een aantal gegevens moet opslaan in een online database. De activiteit kan een begeleidende dienst starten en deze de op te slaan gegevens leveren door een intentie door te geven aan startService()
. De service ontvangt de intent in onStartCommand()
, maakt verbinding met het Internet, en voert de database transactie uit. Als de transactie is voltooid, stopt de service zichzelf en wordt vernietigd.
Voorzichtig: Een service wordt standaard uitgevoerd in hetzelfde proces als de toepassing waarin deze is gedeclareerd en in de hoofdthread van die toepassing. Als uw service intensieve of blokkeringsbewerkingen uitvoert terwijl de gebruiker interactief is met een activiteit van dezelfde toepassing, vertraagt de service de prestaties van de activiteit. Om de prestaties van de toepassing niet te beïnvloeden, start u een nieuwe thread binnen de service.
De Service
class is de basisclass voor alle services. Wanneer u deze klasse uitbreidt, is het belangrijk om een nieuwe thread te creëren waarin de dienst al zijn werk kan voltooien; de dienst gebruikt standaard de hoofdthread van uw toepassing, die de prestaties van elke activiteit die uw toepassing uitvoert kan vertragen.
Het Android-framework biedt ook de IntentService
subklasse van Service
die een worker thread gebruikt om alle startverzoeken af te handelen, een voor een. Het gebruik van deze klasse wordt niet aanbevolen voor nieuwe apps omdat het niet goed zal werken vanaf Android 8 Oreo, als gevolg van de introductie van Achtergronduitvoeringslimieten.Bovendien is het deprecated vanaf Android 11.U kunt JobIntentService gebruiken als vervanging voor IntentService
die compatibel is met nieuwere versies van Android.
De volgende secties beschrijven hoe u uw eigen aangepaste service kunt implementeren, maar u moet sterk overwegen om in plaats daarvan WorkManager te gebruiken voor de meeste use-cases. Raadpleeg de gids voor achtergrondverwerking op Android om te zien of er een oplossing die past bij uw behoeften.
Uitbreiding van de Service klasse
U kunt de Service
klasse uit te breiden om elke inkomende intentie te behandelen. Hier ziet u hoe een basisimplementatie eruit zou kunnen zien:
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(); }}
De voorbeeldcode behandelt alle inkomende oproepen in onStartCommand()
en post het werk naar een Handler
die op een achtergronddraad draait. Het werkt net als een IntentService
en verwerkt alle verzoeken serieel, de een na de ander.U zou de code kunnen wijzigen om het werk op een thread pool uit te voeren, bijvoorbeeld, als u meerdere verzoeken tegelijk wilt uitvoeren.
Merk op dat de onStartCommand()
methode een geheel getal moet retourneren. Het gehele getal is een waarde die beschrijft hoe het systeem de service moet voortzetten in het geval dat het systeem het doodt. De return waarde van onStartCommand()
moet een van de volgende constanten zijn:
START_NOT_STICKY
Als het systeem de service doodt nadatonStartCommand()
is teruggekeerd, maak de service dan niet opnieuw aan tenzij er nog hangende boodschappen zijn om af te leveren. Dit is de veiligste optie om te voorkomen dat uw service wordt uitgevoerd wanneer dat niet nodig is en wanneer uw toepassing gewoon alle onvoltooide taken opnieuw kan starten.START_STICKY
Als het systeem de service stopt nadatonStartCommand()
is teruggekeerd, maakt u de service opnieuw en roept uonStartCommand()
op, maar levert u de laatste intent niet opnieuw af. In plaats daarvan roept het systeemonStartCommand()
op met eenull intent, tenzij er nog in afwachting is van intenties om de service te starten. In dat geval worden die intenties afgeleverd. Dit is geschikt voor mediaspelers (of soortgelijke services) die geen opdrachten uitvoeren, maar voor onbepaalde tijd draaien en op een opdracht wachten.START_REDELIVER_INTENT
Als het systeem de service doodt nadatonStartCommand()
is teruggekeerd, maakt u de service opnieuw en roept uonStartCommand()
aan met de laatste intent die aan de service is afgeleverd. Alle in afwachting zijnde intenties worden op hun beurt afgeleverd. Dit is geschikt voor services die actief een taak uitvoeren die onmiddellijk moet worden hervat, zoals het downloaden van een bestand.
Voor meer details over deze retourwaarden, zie de gekoppelde referentiedocumentatie voor elke constante.
Start een service
U kunt een service starten vanuit een activiteit of een andere applicatiecomponent door een Intent
door te geven aan startService()
of startForegroundService()
. Het Android-systeem roept de methode onStartCommand()
van de service aan en geeft de Intent
door, die aangeeft welke service moet worden gestart.
Opmerking: Als uw app API-niveau 26 of hoger beoogt, legt het systeem beperkingen op voor het gebruiken of maken van achtergronddiensten, tenzij de app zelf zich op de voorgrond bevindt. Als een app een voorgronddienst moet aanmaken, moet de app startForegroundService()
oproepen. Die methode creëert een achtergronddienst, maar de methode signaleert aan het systeem dat de dienst zichzelf naar de voorgrond zal promoveren. Zodra de dienst is gemaakt, moet de dienst zijn startForeground()
methode binnen vijf seconden aanroepen.
Een activiteit kan bijvoorbeeld de voorbeelddienst uit de vorige sectie (HelloService
) starten met behulp van een expliciete intentie met startService()
, zoals hier wordt weergegeven:
Kotlin
Intent(this, HelloService::class.java).also { intent -> startService(intent)}
Java
Intent intent = new Intent(this, HelloService.class);startService(intent);
De methode startService()
keert onmiddellijk terug, en het Android-systeem roept de methode onStartCommand()
van de dienst aan. Als de service nog niet draait, roept het systeem eerst onCreate()
aan, en vervolgensonStartCommand()
.
Als de service niet ook binding biedt, is de intentie die wordt geleverd met startService()
de enige communicatiemogelijkheid tussen de applicatiecomponent en de service. Als u echter wilt dat de service een resultaat terugstuurt, kan de client die de service start een PendingIntent
voor een broadcast (met getBroadcast()
) maken en deze aan de service leveren in de Intent
die de service start. De dienst kan dan de uitzending gebruiken om een resultaat af te leveren.
Meerdere verzoeken om de dienst te starten resulteren in meerdere overeenkomstige aanroepen naar deonStartCommand()
van de dienst. Er is echter slechts één verzoek nodig om de service te stoppen (met stopSelf()
of stopService()
).
Stoppen van een service
Een gestarte service moet zijn eigen levenscyclus beheren. Dat wil zeggen, het systeem stopt niet om de service te vernietigen, tenzij het systeemgeheugen moet herstellen en de service blijft draaien nadat onStartCommand()
is teruggekeerd. De service moet zelf stoppen door stopSelf()
aan te roepen, of een ander component kan hem stoppen door stopService()
aan te roepen.
Als eenmaal is gevraagd om te stoppen met stopSelf()
of stopService()
, vernietigt het systeem de service zo snel als mogelijk.
Als uw dienst meerdere verzoeken aan onStartCommand()
gelijktijdig afhandelt, moet u de dienst niet stoppen wanneer u klaar bent met het verwerken van een startverzoek, aangezien u een nieuw startverzoek zou kunnen hebben ontvangen (stoppen aan het einde van het eerste verzoek zou het tweede verzoek beëindigen). Om dit probleem te voorkomen, kunt u stopSelf(int)
gebruiken om ervoor te zorgen dat uw verzoek om de service te stoppen altijd gebaseerd is op het meest recente startverzoek. Dat wil zeggen, wanneer u stopSelf(int)
aanroept, geeft u de ID door van het startverzoek (de startId
geleverd aan onStartCommand()
) waar uw stopverzoek op reageert. Als de dienst een nieuw startverzoek ontvangt voordat u stopSelf(int)
kunt oproepen, komt de ID niet overeen en stopt de dienst niet.
Waarschuwing: Om te voorkomen dat systeembronnen worden verspild en batterijvermogen wordt verbruikt, moet u ervoor zorgen dat uw toepassing zijn services stopt wanneer deze klaar is met werken.Indien nodig kunnen andere componenten de service stoppen door stopService()
aan te roepen. Zelfs als u binding voor de service inschakelt, moet u de service altijd zelf stoppen als deze ooit een oproep naar onStartCommand()
ontvangt.
Voor meer informatie over de levenscyclus van een service, zie de sectie hieronder over Het beheren van de levenscyclus van een service.
Een gebonden service maken
Een gebonden service is een service die applicatiecomponenten toestaat om eraan te binden door bindService()
aan te roepen om een langdurige verbinding te maken.Het staat in het algemeen niet toe dat componenten hem starten door startService()
aan te roepen.
Maak een gebonden service wanneer u wilt communiceren met de service vanuit activiteiten en andere componenten in uw applicatie of om bepaalde functionaliteit van uw applicatie bloot te stellen aan andere applicaties door middel van interprocess communicatie (IPC).
Om een gebonden service te maken, implementeert u de onBind()
callback methode om een IBinder
terug te sturen die de interface definieert voor communicatie met de service. Andere toepassingscomponenten kunnen dan bindService()
aanroepen om de interface op te halen en methoden op de dienst beginnen aan te roepen. De service leeft alleen om de toepassingscomponent te dienen die eraan is gebonden, dus als er geen componenten zijn die aan de service zijn gebonden, vernietigt het systeem de service. U hoeft een gebonden service niet op dezelfde manier te stoppen als wanneer de service wordt gestart via onStartCommand()
.
Om een gebonden service te maken, moet u de interface definiëren die specificeert hoe een client met de service kan communiceren. Deze interface tussen de service en een client moet een implementatie zijn van IBinder
en is wat uw service moet retourneren van de onBind()
callback methode. Nadat de client de IBinder
heeft ontvangen, kan het beginnen met de interactie met de service via die interface.
Meerdere clients kunnen zich tegelijkertijd binden aan de service. Wanneer een client klaar is met de interactie met de service, roept hij unbindService()
op om de binding op te heffen.Wanneer er geen clients meer aan de service zijn gebonden, vernietigt het systeem de service.
Er zijn meerdere manieren om een gebonden service te implementeren, en de implementatie is gecompliceerder dan een gestarte service. Om deze redenen verschijnt de discussie over gebonden services in een apart document over gebonden services.
Meldingen naar de gebruiker sturen
Wanneer een service draait, kan deze de gebruiker op de hoogte stellen van gebeurtenissen met behulp van Toast-meldingen of Statusbalk-meldingen.
Een Toast-melding is een bericht dat slechts even op het oppervlak van het huidige venster verschijnt voordat het weer verdwijnt. Een statusbalk-melding geeft een pictogram in de statusbalk met een bericht, dat de gebruiker kan selecteren om een actie te ondernemen (zoals het starten van een activiteit).
In de regel is een statusbalk-melding de beste techniek om te gebruiken wanneer achtergrondwerk, zoals het downloaden van een bestand, is voltooid, en de gebruiker er nu iets mee kan doen. Wanneer de gebruiker de melding selecteert vanuit de uitgebreide weergave, kan de melding een activiteit starten (zoals het weergeven van het gedownloade bestand).
Zie de Toast Notifications of Status Bar Notificationsdeveloper guides voor meer informatie.
Het beheren van de levenscyclus van een service
De levenscyclus van een service is veel eenvoudiger dan die van een activiteit. Het is echter nog belangrijker dat u goed let op hoe uw service wordt gemaakt en vernietigd, omdat een service op de achtergrond kan draaien zonder dat de gebruiker zich daarvan bewust is.
De levenscyclus van een service – van het moment dat deze wordt gemaakt tot het moment dat deze wordt vernietigd – kan een van deze twee paden volgen:
- Een gestarte service
De service wordt gemaakt wanneer een andere component
startService()
aanroept. De service draait dan voor onbepaalde tijd en moet zichzelf stoppen doorstopSelf()
aan te roepen. Een ander component kan de service ook stoppen doorstopService()
aan te roepen. Wanneer de service is gestopt, vernietigt het systeem deze. - Een gebonden service
De service wordt aangemaakt wanneer een ander component (een client)
bindService()
aanroept. De client communiceert vervolgens met de service via eenIBinder
-interface. De client kan de verbinding sluiten doorunbindService()
aan te roepen. Meerdere clients kunnen zich binden aan dezelfde service en wanneer ze zich allemaal ontkoppelen, vernietigt het systeem de service. De service hoeft zichzelf niet te stoppen.
Deze twee paden zijn niet geheel gescheiden. U kunt zich binden aan een dienst die al is gestart met startService()
. U kunt bijvoorbeeld een achtergrondmuziekdienst starten door startService()
aan te roepen met een Intent
die de af te spelen muziek identificeert. Later, wanneer de gebruiker controle over de speler wil uitoefenen of informatie over het huidige nummer wil krijgen, kan een activiteit zich aan de dienst binden door bindService()
aan te roepen. In dit soort gevallen stopt stopService()
of stopSelf()
de service niet totdat alle clients de binding hebben opgeheven.
Implementeren van de lifecycle callbacks
Net als een activity heeft een service lifecycle callback methods die u kunt implementeren om veranderingen in de status van de service in de gaten te houden en op de juiste momenten werk te verrichten. De volgende skeletdienst demonstreert elk van de lifecycle-methoden:
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 }}
Opmerking: in tegenstelling tot de callback-methoden van de activiteitslevenscyclus, bent u niet verplicht om de superklasse-implementatie van deze callback-methoden aan te roepen.
Figuur 2. De levenscyclus van de service. Het linker diagram toont de levenscyclus als de service is gemaakt met startService()
en het rechter diagram toont de levenscyclus als de service is gemaakt met bindService()
.
Figuur 2 illustreert de typische callback-methoden voor een service. Hoewel de figuur onderscheid maakt tussen diensten die zijn aangemaakt met startService()
en diensten die zijn aangemaakt met bindService()
, moet u in gedachten houden dat elke dienst, ongeacht hoe deze is gestart, mogelijk cliënten kan binden. Een dienst die in eerste instantie is gestart met onStartCommand()
(door een cliënt die startService()
aanroept) kan nog steeds een oproep naar onBind()
ontvangen (wanneer een cliënt bindService()
aanroept).
Door deze methoden te implementeren, kunt u deze twee geneste lussen van de levenscyclus van de service bewaken:
- De volledige levensduur van een service vindt plaats tussen het moment dat
onCreate()
wordt aangeroepen en het moment datonDestroy()
terugkeert. Net als een activiteit, doet een dienst zijn eerste opzet inonCreate()
en geeft alle resterende middelen vrij inonDestroy()
. Bijvoorbeeld, een service voor het afspelen van muziek kan de thread waar de muziek wordt afgespeeld inonCreate()
aanmaken, en kan dan de thread inonDestroy()
stoppen.Note: De
onCreate()
enonDestroy()
methodes worden voor alle services aangeroepen, of ze nu doorstartService()
ofbindService()
zijn gemaakt. - De actieve levensduur van een dienst begint met een oproep aan
onStartCommand()
ofonBind()
.Elke methode krijgt deIntent
die is doorgegeven aanstartService()
ofbindService()
.Als de dienst wordt gestart, eindigt de actieve levensduur op hetzelfde moment dat de gehele levensduur eindigt (de dienst is nog steeds actief, zelfs nadat
onStartCommand()
is teruggekeerd). Als de service is gebonden, eindigt de actieve levensduur wanneeronUnbind()
terugkeert.
Note: Hoewel een gestarte service wordt gestopt door een oproep aan ofwel stopSelf()
of stopService()
, is er geen respectievelijke callback voor de service (er is geen onStop()
callback). Tenzij de service is gebonden aan een client, vernietigt het systeem deze wanneer de service wordt gestopt-onDestroy()
is de enige callback die wordt ontvangen.
Voor meer informatie over het maken van een service die binding biedt, zie het Bound Services document, dat meer informatie bevat over de onRebind()
callback methode in de sectie over het beheren van de levenscyclus van een gebonden service.