Oversigt over tjenester

En Service er en applikationskomponent, der kan udføre langvarige operationer i baggrunden. Den giver ikke en brugergrænseflade. I begyndelsen kan en tjeneste fortsætte med at køre i et stykke tid, selv efter at brugeren skifter til et andet program. Desuden kan en komponent binde sig til en tjeneste for at interagere med den og endda udføre IPC-kommunikation (Interprocess Communication). En tjeneste kan f.eks. håndtere netværkstransaktioner, afspille musik, udføre fil I/O eller interagere med en indholdsudbyder, alt sammen i baggrunden.

Varsel: En tjeneste kører i hovedtråden i hostingprocessen; tjenesten opretter ikke sin egen tråd og kører ikke i en separat proces, medmindre du angiver andet. Du bør køre alle blokerende operationer i en separat tråd i tjenesten for at undgå ANR-fejl (ApplicationNot Responding).

Typer af tjenester

Dette er de tre forskellige typer tjenester:

Forgrundstjeneste

En forgrundstjeneste udfører en operation, som er synlig for brugeren. En lyd-app vil f.eks. bruge en forgrundstjeneste til at afspille et lydspor. Foreground-tjenester skal vise en notifikation. Forgrundstjenester fortsætter med at køre, selv når brugeren ikke interagerer med appen.

Når du bruger en forgrundstjeneste, skal du vise en meddelelse, så brugerne er aktivt opmærksomme på, at tjenesten kører. Denne meddelelse kan ikke afvises, medmindre tjenesten enten stoppes eller fjernes fra forgrunden.

Læs mere om, hvordan du konfigurerer forgrundstjenester i din app.

Bemærk: WorkManager API’et tilbyder en fleksibel måde at planlægge opgaver på, og er i stand til at køre disse opgaver som forgrundstjenester, hvis det er nødvendigt. I mange tilfælde er det at bruge WorkManager at foretrække frem for at bruge forgrundstjenester direkte.

Baggrund En baggrundstjeneste udfører en operation, der ikke direkte bemærkes af brugeren. Hvis en app f.eks. bruger en tjeneste til at komprimere sit lager, vil det normalt være en baggrundstjeneste.

Bemærk: Hvis din app er rettet mod API-niveau 26 eller højere, pålægger systemet begrænsninger for kørsel af baggrundstjenester, når selve appen ikke er i forgrunden. I de fleste situationer bør du f.eks. ikke få adgang til placeringsoplysninger fra baggrunden. I stedet skal du planlægge opgaver ved hjælp af WorkManager.

Bundet En tjeneste er bundet, når en programkomponent binder sig til den ved at kaldebindService(). En bundet tjeneste tilbyder en klient-server-grænseflade, der gør det muligt for komponenter at interagere med tjenesten, sende anmodninger, modtage resultater og endda gøre det på tværs af processer med IPC (interprocess communication). En bundet tjeneste kører kun, så længe en anden programkomponent er bundet til den. Flere komponenter kan binde sig til tjenesten på én gang, men når alle komponenterne ophæver bindingen, bliver tjenesten ødelagt.

Selv om denne dokumentation generelt diskuterer startede og bundne tjenester separat, kan din tjeneste fungere på begge måder – den kan være startet (for at køre på ubestemt tid) og også tillade binding. Det er blot et spørgsmål om, hvorvidt du implementerer et par callback-metoder: onStartCommand() for at tillade komponenter at starte den og onBind() for at tillade binding.

Uanset om din tjeneste er startet, bundet eller begge dele, kan enhver programkomponent bruge tjenesten (selv fra et separat program) på samme måde, som enhver komponent kan bruge en aktivitet, ved at starte den med en Intent. Du kan dog erklære tjenesten som privat i manifestfilen og blokere adgangen fra andre programmer.Dette diskuteres mere i afsnittet om Deklaration af tjenesten i manifestet.

Valg mellem en tjeneste og en tråd

En tjeneste er simpelthen en komponent, der kan køre i baggrunden, selv når brugeren ikke interagerer med dit program, så du bør kun oprette en tjeneste, hvis det er det, du har brug for.

Hvis du skal udføre arbejde uden for din hovedtråd, men kun mens brugeren interagerer med dit program, bør du i stedet oprette en ny tråd i forbindelse med en anden programkomponent. Hvis du f.eks. vil afspille noget musik, men kun mens din aktivitet kører, kan du oprette en tråd i onCreate(), begynde at køre den i onStart() og stoppe den i onStop().Overvej også at bruge trådpuljer og eksekutorer fra java.util.concurrent-pakken eller Kotlin-coroutiner i stedet for den traditionelleThread-klasse. Se dokumentetThreading on Android for at få flere oplysninger om flytning af udførelse til baggrundstråde.

Husk, at hvis du bruger en tjeneste, kører den stadig som standard i programmets hovedtråd, så du bør stadig oprette en ny tråd i tjenesten, hvis den udfører intensive eller blokerende operationer.

Det grundlæggende

For at oprette en tjeneste skal du oprette en underklasse af Service eller bruge en af dens eksisterende underklasser. I din implementering skal du overskrive nogle callback-metoder, der håndterer vigtige aspekter af tjenestens livscyklus, og du skal tilvejebringe en mekanisme, der gør det muligt for komponenterne at knytte sig til tjenesten, hvis det er relevant. Disse er de vigtigste callback-metoder, som du bør tilsidesætte:

onStartCommand()Systemet påkalder denne metode ved at kaldestartService(), når en anden komponent (f.eks. en aktivitet) anmoder om, at tjenesten startes.Når denne metode udføres, er tjenesten startet og kan køre i baggrunden på ubestemt tid. Hvis du implementerer dette, er det dit ansvar at stoppe tjenesten, når dens arbejde er færdigt, ved at kalde

stopSelf()ellerstopService(). Hvis du kun ønsker at levere binding, behøver du ikke at implementere denne metode.onBind()Systemet påkalder denne metode ved at kaldebindService(), når en anden komponent ønsker at binde sig til tjenesten (f.eks. for at udføre RPC).I din implementering af denne metode skal du levere en grænseflade, som klienterne bruger til at kommunikere med tjenesten ved at returnere enIBinder. Du skal altidimplementere denne metode; hvis du imidlertid ikke ønsker at tillade binding, skal du returnere null.onCreate()Systemet påkalder denne metode for at udføre engangsopsætningsprocedurer, når tjenesten oprettes første gang (før den kalder entenonStartCommand()elleronBind()). Hvis tjenesten allerede er kørt, kaldes denne metode ikke.onDestroy()Systemet påkalder denne metode, når tjenesten ikke længere bruges og destrueres.Din tjeneste bør implementere dette for at rydde op i eventuelle ressourcer som f.eks. tråde, registrerede lyttere eller modtagere. Dette er det sidste kald, som tjenesten modtager.

Hvis en komponent starter tjenesten ved at kalde startService() (hvilket resulterer i et kald til onStartCommand()), fortsætter tjenesten med at køre, indtil den stopper sig selv med stopSelf() eller en andenkomponent stopper den ved at kalde stopService().

Hvis en komponent kalder bindService() for at oprette tjenesten, og onStartCommand() ikke kaldes, kører tjenesten kun, så længe komponenten er bundet til den. Når tjenesten er løsnet fra alle dens klienter, ødelægger systemet den.

Android-systemet stopper kun en tjeneste, når hukommelsen er lav, og det skal genvinde systemressourcer til den aktivitet, der har brugerens fokus. Hvis tjenesten er bundet til en aktivitet, der har brugerfokus, er der mindre sandsynlighed for, at den bliver dræbt; hvis tjenesten er erklæret til at køre i forgrunden, bliver den sjældent dræbt.Hvis tjenesten startes og kører længe, sænker systemet dens position på listen over baggrundsopgaver over tid, og tjenesten bliver meget modtagelig for at blive dræbt – hvis din tjeneste startes, skal du designe den til at kunne håndtere systemets genstart på en elegant måde. Hvis systemet dræber din tjeneste, genstarter det den, så snart der bliver ressourcer til rådighed, men dette afhænger også af den værdi, du returnerer fra onStartCommand(). Du kan finde flere oplysninger om, hvornår systemet kan ødelægge en tjeneste, i dokumentet Processes and Threadingdocument.

I de følgende afsnit kan du se, hvordan du kan oprette tjenestemetodernestartService() ogbindService(), og hvordan du kan bruge dem fra andre programkomponenter.

Deklaration af en tjeneste i manifestet

Du skal deklarere alle tjenester i din programsmanifestfil, ligesom du gør for aktiviteter og andre komponenter.

For at deklarere din tjeneste skal du tilføje et <service>-element som et barn af <application>-elementet. Her er et eksempel:

<manifest ... > ... <application ... > <service android:name=".ExampleService" /> ... </application></manifest>

Se <service>-elementreferencen for at få flere oplysninger om, hvordan du erklærer din tjeneste i manifestet.

Der er andre attributter, som du kan medtage i <service>-elementet for at definere egenskaber som f.eks. de tilladelser, der kræves for at starte tjenesten, og den proces, som tjenesten skal køre i. android:name-attributten er den eneste obligatoriske attribut – den angiver klassens navn for tjenesten. Når du offentliggør din applikation, skal du lade dette navn forblive uændret for at undgå risikoen for brudkode på grund af afhængighed af eksplicitte intentioner om at starte eller binde tjenesten (læs blogindlægget Ting, der ikke kan ændres).

Varsel: For at sikre, at din app er sikker, skal du altid bruge en eksplicit hensigt, når du starter en Service, og du må ikke angive hensigtfiltre for dine tjenester. Brug af en implicit hensigt til at starte en tjeneste er en sikkerhedsrisiko, fordi du ikke kan være sikker på, hvilken tjeneste der reagerer på hensigten, og brugeren kan ikke se, hvilken tjeneste der startes. Fra og med Android 5.0 (API-niveau 21) kaster systemet en undtagelse, hvis du kalder bindService() med en implicit hensigt.

Du kan sikre, at din tjeneste kun er tilgængelig for din app ved atinkludere attributten android:exported og indstille den til false. Dette forhindrer effektivt andre apps i at starte din tjeneste, selv når du bruger en eksplicit hensigt.

Bemærk: Brugere kan se, hvilke tjenester der kører på deres enhed. Hvis de ser en tjeneste, som de ikke kan genkende eller stoler på, kan de stoppe tjenesten. For at undgå at få din tjeneste stoppet ved et uheld af brugerne skal du tilføje attributten android:description til <service>-elementet i dit appmanifest. I beskrivelsen skal du give en kort sætning, der forklarer, hvad tjenesten gør, og hvilke fordele den giver.

Skabelse af en startet tjeneste

En startet tjeneste er en tjeneste, som en anden komponent starter ved at kalde startService(), hvilket resulterer i et kald til tjenestensonStartCommand() metode.

Når en tjeneste er startet, har den en livscyklus, der er uafhængig af den komponent, der startede den. Tjenesten kan køre i baggrunden på ubestemt tid, selv om den komponent, der startede den, bliver ødelagt. Tjenesten skal derfor stoppe sig selv, når dens arbejde er færdigt, ved at kalde stopSelf(), eller en anden komponent kan stoppe den ved at kalde stopService().

En programkomponent, f.eks. en aktivitet, kan starte tjenesten ved at kalde startService() og overdrage en Intent, der angiver tjenesten og indeholder eventuelle data, som tjenesten skal bruge. Tjenesten modtager denne Intent i onStartCommand()-metoden.

Sæt f.eks., at en aktivitet skal gemme nogle data i en onlinedatabase. Aktivitetenkan starte en ledsagetjeneste og levere den de data, der skal gemmes, ved at sende en hensigt til startService(). Tjenesten modtager hensigten i onStartCommand(), opretter forbindelse til internettet og gennemfører databasetransaktionen. Når transaktionen er afsluttet, stopper tjenesten sig selv og destrueres.

Attende: En tjeneste kører i samme proces som det program, hvori den er erklæret, og som standard i hovedtråden i dette program. Hvis din tjeneste udfører intensive eller blokerende operationer, mens brugeren interagerer med en aktivitet fra det samme program, sænker tjenesten aktivitetens ydeevne. Hvis du vil undgå at påvirke applikationspræstationen, skal du starte en ny tråd inde i tjenesten.

Klassen Service er basisklassen for alle tjenester. Når du udvider denne klasse, er det vigtigt at oprette en ny tråd, hvori tjenesten kan udføre alt sit arbejde; tjenesten bruger som standard din programs hovedtråd, hvilket kan sænke ydeevnen for enhver aktivitet, som din applikation kører.

Android-rammen indeholder også IntentServiceunderklassen til Service, som bruger en undertråd til at håndtere alle startforespørgsler, én ad gangen. Det anbefales ikke at bruge denne klasse til nye apps, da den ikke fungerer godt fra og med Android 8 Oreo på grund af indførelsen af begrænsninger for udførelse i baggrunden.Desuden er den forældet fra og med Android 11.Du kan bruge JobIntentService som erstatning for IntentService, der er kompatibel med nyere versioner af Android.

De følgende afsnit beskriver, hvordan du kan implementere din egen brugerdefinerede tjeneste, men du bør kraftigt overveje at bruge WorkManager i stedet for i de fleste anvendelsestilfælde. Se vejledningen om baggrundsbehandling på Android for at se, om der findes en løsning, der passer til dine behov.

Udvidelse af tjenesteklassen

Du kan udvide Service-klassen til at håndtere hver enkelt indgående hensigt. Sådan kan en grundlæggende implementering se ud:

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(); }}

Eksempelkoden håndterer alle indgående kald i onStartCommand()og sender arbejdet til en Handler, der kører på en baggrundstråd. Den fungerer ligesom en IntentService og behandler alle anmodninger serielt, den ene efter den anden.Du kan f.eks. ændre koden til at køre arbejdet på en trådpulje, hvis du ønsker at køre flere anmodninger samtidig.

Bemærk, at onStartCommand()-metoden skal returnere et heltal. Heltallet er en værdi, der beskriver, hvordan systemet skal fortsætte tjenesten i dettilfælde, at systemet dræber den. Returværdien fra onStartCommand() skal være en af følgende konstanter:

START_NOT_STICKYHvis systemet dræber tjenesten, efter atonStartCommand()har returneret, skal tjenesten ikke genskabes, medmindre der er ventende henstillinger, der skal leveres. Dette er den sikreste mulighed for at undgå at køre tjenesten, når det ikke er nødvendigt, og når dit program blot kan genstarte eventuelle ufærdige job, der ikke er afsluttet.START_STICKYHvis systemet dræber tjenesten, efter atonStartCommand()er vendt tilbage, skal du genskabe tjenesten og kaldeonStartCommand(), men du skal ikke levere den sidste hensigt igen.I stedet kalder systemetonStartCommand()med enull intent, medmindre der er ventende hensigter til at starte tjenesten. I så fald leveres disse hensigter. Dette er velegnet til medieafspillere (eller lignende tjenester), som ikke udfører kommandoer, men som kører på ubestemt tid og venter på et job.START_REDELIVER_INTENTHvis systemet dræber tjenesten, efter atonStartCommand()vender tilbage, skal du genskabe tjenesten og kaldeonStartCommand()med den sidste hensigt, der blev leveret til tjenesten. Eventuelle ventende intentioner leveres på skift. Dette er velegnet til tjenester, der aktivt udfører et job, som straks skal genoptages, f.eks. downloading af en fil.

For yderligere oplysninger om disse returværdier henvises til den linkede referencedokumentation for hver konstant.

Start af en tjeneste

Du kan starte en tjeneste fra en aktivitet eller en anden programkomponent ved at overdrage en Intent til startService() eller startForegroundService(). Android-systemet kalder tjenestens onStartCommand()-metode og giver den Intent, som angiver, hvilken tjeneste der skal startes.

Bemærk: Hvis din app er rettet mod API-niveau 26 eller højere, pålægger systemet begrænsninger for brug eller oprettelse af baggrundstjenester, medmindre selve appen er i forgrunden. Hvis en app har brug for at oprette en forgrundstjeneste, skal appen kalde startForegroundService(). Denne metode opretter en baggrundstjeneste, men metoden sender et signal til systemet om, at tjenesten vil blive sat i forgrunden. Når tjenesten er blevet oprettet, skal tjenesten kalde sin startForeground()-metode inden for fem sekunder.

En aktivitet kan f.eks. starte eksempeltjenesten i det foregående afsnit (HelloService) ved hjælp af en eksplicit hensigt med startService(), som vist her:

Kotlin

Intent(this, HelloService::class.java).also { intent -> startService(intent)}

Java

Intent intent = new Intent(this, HelloService.class);startService(intent);

Metoden startService() vender straks tilbage, og Android-systemet kalder tjenestens onStartCommand()-metode. Hvis tjenesten ikke allerede kører, kalder systemet først onCreate(), og derefter kalder detonStartCommand().

Hvis tjenesten ikke også leverer binding, er den hensigt, der leveres med startService(), den eneste kommunikationsmåde mellem applikationskomponenten og tjenesten. Hvis du imidlertid ønsker, at tjenesten skal sende et resultat tilbage, kan den klient, der starter tjenesten, oprette en PendingIntent til en udsendelse(med getBroadcast()) og levere den til tjenesten i Intent, der starter tjenesten. Tjenesten kan derefter bruge broadcasten til at levere et resultat.

Multiple requests to start the service result in multiple corresponding calls to the service’sonStartCommand(). Der kræves dog kun én anmodning om at stoppe tjenesten (med stopSelf() eller stopService()) for at stoppe den.

Stop af en tjeneste

En startet tjeneste skal administrere sin egen livscyklus. Det vil sige, at systemet ikke stopper eller ødelægger tjenesten, medmindre det skal gendanne systemhukommelse, og tjenesten fortsætter med at køre, efter at onStartCommand() vender tilbage. Tjenesten skal selv stoppe ved at kalde stopSelf(), eller en anden komponent kan stoppe den ved at kalde stopService().

Når systemet anmodes om at stoppe med stopSelf() eller stopService(), ødelægger det tjenesten så hurtigt som muligt.

Hvis din tjeneste håndterer flere anmodninger til onStartCommand() samtidig, bør du ikke stoppe tjenesten, når du er færdig med at behandle en startanmodning, da du måske har modtaget en ny startanmodning (hvis du stopper ved afslutningen af den første anmodning, vil du afslutte den anden). For at undgådette problem kan du bruge stopSelf(int) til at sikre, at din anmodning om at stoppe tjenesten altid er baseret på den seneste startanmodning. Det vil sige, at når du kalder stopSelf(int), skal du overdrage ID’et for den startanmodning (den startId, der er leveret til onStartCommand()), som din stopanmodning svarer til. Hvis tjenesten derefter modtager en ny startanmodning, før du kan kalde stopSelf(int), passer ID’et ikke sammen, og tjenesten stopper ikke.

Forsigtig: Hvis du vil undgå at spilde systemressourcer og forbruge batteristrøm, skal du sørge for, at din applikation stopper sine tjenester, når den er færdig med at arbejde.Om nødvendigt kan andre komponenter stoppe tjenesten ved at kalde stopService(). Selv hvis du aktiverer binding for tjenesten, skal du altid selv stoppe tjenesten, hvis den nogensinde modtager et kald til onStartCommand().

For yderligere oplysninger om en tjenestes livscyklus henvises til afsnittet nedenfor om Håndtering af en tjenestes livscyklus.

Opretning af en bunden tjeneste

En bunden tjeneste er en tjeneste, der gør det muligt for programkomponenter at binde til den ved at kalde bindService() for at oprette en langvarig forbindelse.Den tillader normalt ikke, at komponenter starter den ved at kalde startService().

Opret en bundet tjeneste, når du ønsker at interagere med tjenesten fra aktiviteter og andre komponenter i din applikation eller at udsætte nogle af applikationens funktioner for andre applikationer via interproceskommunikation (IPC).

For at oprette en bundet tjeneste skal du implementere onBind() callback-metoden for at returnere en IBinder, der definerer grænsefladen for kommunikation med tjenesten. Andre programkomponenter kan derefter kalde bindService() for at hente grænsefladen og begynde at kalde metoder på tjenesten. Tjenesten lever kun for at betjene den programkomponent, der er bundet til den, så når der ikke er nogen komponenter bundet til tjenesten, destruerer systemet den.Du behøver ikke at stoppe en bundet tjeneste på samme måde, som når tjenesten startes via onStartCommand().

For at oprette en bundet tjeneste skal du definere den grænseflade, der angiver, hvordan en klient kan kommunikere med tjenesten. Denne grænseflade mellem tjenesten og en klient skal være en implementering af IBinder og er det, som din tjeneste skal returnere fra onBind() callback-metoden. Når klienten har modtaget IBinder, kan den begynde at interagere med tjenesten via denne grænseflade.

Multiple clients can bind to the service simultaneously. Når en klient er færdig med at interagere med tjenesten, kalder den unbindService() for at ophæve bindingen.Når der ikke er nogen klienter, der er bundet til tjenesten, ødelægger systemet tjenesten.

Der er flere måder at implementere en bundet tjeneste på, og implementeringen er mere kompliceret end en startet tjeneste. Af disse grunde vises diskussionen om bundne tjenester i et separat dokument om bundne tjenester.

Sendelse af meddelelser til brugeren

Når en tjeneste kører, kan den give brugeren besked om hændelser ved hjælp af Toast Notifications eller Status Bar Notifications.

En toastmeddelelse er en meddelelse, der kun vises på overfladen af det aktuelle vindue i et øjeblik, før den forsvinder. En meddelelse i statuslinjen giver et ikon i statuslinjen med en meddelelse, som brugeren kan vælge for at foretage en handling (f.eks. starte en aktivitet).

En meddelelse i statuslinjen er normalt den bedste teknik at bruge, når baggrundsarbejde, f.eks. en fildownload, er afsluttet, og brugeren nu kan handle på det. Når brugeren vælger meddelelsen i den udvidede visning, kan meddelelsen starte en aktivitet (f.eks. for at vise den downloadede fil).

Se Toast Notifications eller Status Bar Notifications-udviklervejledningerne for at få flere oplysninger.

Håndtering af en tjenestes livscyklus

Livscyklus for en tjeneste er meget enklere end for en aktivitet. Det er dog endnu vigtigere, at du er meget opmærksom på, hvordan din tjeneste oprettes og destrueres, fordi en tjeneste kan køre i baggrunden, uden at brugeren er klar over det.

Tjenestens livscyklus – fra den oprettes til den destrueres – kan følge en af disse to veje:

  • En startet tjeneste

    Tjenesten oprettes, når en anden komponent kalder startService(). Tjenesten kører derefter på ubestemt tid og skal stoppe sig selv ved at kalde stopSelf(). En anden komponent kan også stoppe tjenesten ved at kalde stopService(). Når tjenesten stoppes, destrueres den af systemet.

  • En bundet tjeneste

    Tjenesten oprettes, når en anden komponent (en klient) kalder bindService(). Klienten kommunikerer derefter med servicen gennem en IBinder grænseflade. Klienten kan lukke forbindelsen ved at kaldeunbindService(). Flere klienter kan binde sig til den samme tjeneste, og når alle klienterne ophæver forbindelsen, ødelægger systemet tjenesten. Tjenesten behøver ikke at stoppe sig selv.

Disse to veje er ikke helt adskilte. Du kan binde til en tjeneste, der allerede er startet, med startService(). Du kan f.eks. starte en baggrundsmusiktjeneste ved at kalde startService() med en Intent, der identificerer den musik, der skal afspilles. Senere, eventuelt når brugeren ønsker at udøve kontrol over afspilleren eller få oplysninger om den aktuelle sang, kan en aktivitet binde til tjenesten ved at kalde bindService(). I tilfælde som dette stopper stopService() eller stopSelf() faktisk ikke tjenesten, før alle klienterne afbindes.

Implementering af livscyklus-callbacks

Som en aktivitet har en tjeneste livscyklus-callbackmetoder, som du kan implementere for at overvågeændringer i tjenestens tilstand og udføre arbejde på de relevante tidspunkter. Følgende skeletonservice demonstrerer hver af livscyklusmetoderne:

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 }}

Bemærk: I modsætning til aktivitetens livscyklus-callbackmetoder er du ikke forpligtet til at kalde superklassens implementering af disse callbackmetoder.

Figur 2. Tjenestens livscyklus. Diagrammet til venstre viser livscyklusen, når tjenesten oprettes med startService(), og diagrammet til højre viser livscyklusen, når tjenesten oprettes med bindService().

Figur 2 illustrerer de typiske callback-metoder for en tjeneste. Selv om figuren adskiller tjenester, der oprettes med startService(), fra tjenester, der oprettes med bindService(), skal du huske på, at enhver tjeneste, uanset hvordan den er startet, potentielt kan tillade klienter at binde sig til den.En tjeneste, der oprindeligt blev startet med onStartCommand() (af en klient, der kalder startService())kan stadig modtage et kald til onBind() (når en klient kalder bindService()).

Gennem implementering af disse metoder kan du overvåge disse to indlejrede sløjfer i tjenestens livscyklus:

  • Hele en tjenestes levetid finder sted mellem det tidspunkt, hvor onCreate() kaldes, og det tidspunkt, hvor onDestroy() vender tilbage. Ligesom en aktivitet foretager en tjeneste sin indledende opsætning i onCreate() og frigiver alle resterende ressourcer i onDestroy(). F.eks. kan en musikafspilningstjeneste oprette tråden, hvor musikken afspilles, i onCreate(), og derefter kan den stoppe tråden i onDestroy().

    Bemærk: Metoderne onCreate()og onDestroy() kaldes for alle tjenester, uanset om de er oprettet af startService() eller bindService().

  • Den aktive levetid for en tjeneste begynder med et kald til enten onStartCommand() eller onBind().Hver metode får overdraget den Intent, der blev overgivet til enten startService() eller bindService().

    Hvis tjenesten startes, slutter den aktive levetid på samme tidspunkt, som hele levetiden slutter (tjenesten er stadig aktiv, selv efter at onStartCommand() vender tilbage). Hvis tjenesten er bundet, slutter den aktive levetid, når onUnbind() vender tilbage.

Bemærk: Selv om en startet tjeneste stoppes ved et kald til enten stopSelf() eller stopService(), er der ikke et tilsvarende callback for tjenesten (der er ikke noget onStop() callback). Medmindre tjenesten er bundet til en klient, ødelægger systemet den, når tjenesten stoppes – onDestroy() er det eneste callback, der modtages.

For yderligere oplysninger om oprettelse af en tjeneste, der giver binding, se dokumentet Bundene tjenester, som indeholder flere oplysninger om onRebind()callback-metoden i afsnittet om Håndtering af livscyklus for en bunden tjeneste.

Skriv et svar

Din e-mailadresse vil ikke blive publiceret.