Prezentare generală a serviciilor

Un Service este o componentă a aplicației care poate efectua operații de lungă durată în fundal. Ea nu oferă o interfață cu utilizatorul. În mod normal, un serviciu poate continua să funcționeze pentru o anumită perioadă de timp, chiar și după ce utilizatorul trece la o altă aplicație. În plus, o componentă se poate lega de un serviciu pentru a interacționa cu acesta și chiar pentru a realiza o comunicare între procese (IPC). De exemplu, un serviciu poate gestiona tranzacții de rețea, poate reda muzică, poate efectua I/O de fișiere sau poate interacționa cu un furnizor de conținut, toate acestea din fundal.

Atenție: Un serviciu rulează în firul principal al procesului său de găzduire; serviciul nu-și creează propriul fir și nu rulează într-un proces separat, cu excepția cazului în care se specifică altfel. Ar trebui să executați orice operație de blocare pe un fir separat în cadrul serviciului pentru a evita erorile ANR (ApplicationNot Responding).

Tipuri de servicii

Acestea sunt cele trei tipuri diferite de servicii:

În prim-plan

Un serviciu în prim-plan efectuează o anumită operație care este vizibilă pentru utilizator. De exemplu, o aplicație audio ar folosi un serviciu de prim-plan pentru a reda o piesă audio. Serviciile de prim-plan trebuie să afișeze o notificare. Serviciile de prim-plan continuă să funcționeze chiar și atunci când utilizatorul nu interacționează cu aplicația.

Când utilizați un serviciu de prim-plan, trebuie să afișați o notificare, astfel încât utilizatorii să fie conștienți în mod activ de faptul că serviciul funcționează. Această notificare nu poate fi respinsă decât dacă serviciul este fie oprit, fie eliminat din prim-plan.

Aflați mai multe despre cum să configurați serviciile de prim-plan în aplicația dumneavoastră.

Notă: API-ul WorkManager oferă o modalitate flexibilă de programare a sarcinilor și este capabil să ruleze aceste sarcini ca servicii de prim-plan, dacă este necesar. În multe cazuri, utilizarea WorkManager este preferabilă utilizării directe a serviciilor în prim-plan.

Background Un serviciu de background efectuează o operațiune care nu este observată direct de către utilizator. De exemplu, dacă o aplicație folosește un serviciu pentru a-și compacta spațiul de stocare, acesta ar fi, de obicei, un serviciu de fundal.

Notă: Dacă aplicația dvs. vizează nivelul API 26 sau mai mare, sistemul impune restricții privind rularea serviciilor de fundal atunci când aplicația însăși nu se află în prim-plan. În majoritatea situațiilor, de exemplu, nu ar trebui să accesați informațiile de localizare din fundal. În schimb, programați sarcinile cu ajutorul WorkManager.

Legat Un serviciu este legat atunci când o componentă a aplicației se leagă de el prin apelareabindService(). Un serviciu legat oferă o interfață client-server care permite componentelor să interacționeze cu serviciul, să trimită cereri, să primească rezultate și chiar să facă acest lucru între procese cu comunicare interproces (IPC). Un serviciu legat funcționează numai atât timp cât o altă componentă a aplicației este legată la el. Mai multe componente se pot lega la serviciu în același timp, dar atunci când toate se dezlipesc, serviciul este distrus.

Deși această documentație discută, în general, separat serviciile pornite și cele legate,serviciul dumneavoastră poate funcționa în ambele sensuri – poate fi pornit (pentru a rula pe termen nelimitat) și, de asemenea, permite legarea. Este pur și simplu o chestiune de a implementa sau nu câteva metode de callback: onStartCommand() pentru a permite componentelor să îl pornească și onBind() pentru a permite legarea.

Indiferent dacă serviciul dumneavoastră este pornit, legat sau ambele, orice componentă a aplicației poate utiliza serviciul (chiar și dintr-o aplicație separată) în același mod în care orice componentă poate utiliza o activitate – prin pornirea acesteia cu un Intent. Cu toate acestea, puteți declara serviciul ca fiind privat în fișierul manifest și să blocați accesul altor aplicații.Acest lucru este discutat mai mult în secțiunea despre Declararea serviciului în manifest.

Alegerea între un serviciu și un fir de execuție

Un serviciu este pur și simplu o componentă care poate rula în fundal, chiar și atunci când utilizatorul nu interacționează cu aplicația dumneavoastră, deci ar trebui să creați un serviciu numai dacă de asta aveți nevoie.

Dacă trebuie să efectuați lucrări în afara firului principal, dar numai în timp ce utilizatorul interacționează cu aplicația dumneavoastră, ar trebui în schimb să creați un nou fir în contextul unei alte componente a aplicației. De exemplu, dacă doriți să redați niște muzică, dar numai în timp ce activitatea dvs. este în curs de desfășurare,ați putea crea un fir în onCreate(), să începeți să îl executați în onStart() și să îl opriți în onStop().De asemenea, luați în considerare utilizarea pool-urilor de fire și a executorilor din pachetul java.util.concurrent sau a corutinelor Kotlin în loc de clasa tradiționalăThread. Consultați documentulThreading on Android pentru mai multe informații despre mutarea execuției pe fire de execuție din fundal.

Amintiți-vă că, dacă utilizați un serviciu, acesta rulează în continuare în firul principal al aplicației dvs. în mod implicit, astfel încât ar trebui să creați în continuare un nou fir de execuție în cadrul serviciului dacă acesta efectuează operații intensive sau blocante.

Bazele

Pentru a crea un serviciu, trebuie să creați o subclasă a Service sau să utilizați una dintre subclasele sale existente. În implementarea dumneavoastră, trebuie să suprascrieți unele metode de callback care gestionează aspecte cheie ale ciclului de viață al serviciului și să furnizați un mecanism care să permită componentelor să se lege de serviciu, dacă este cazul. Acestea sunt cele mai importante metode de callback pe care trebuie să le suprascrieți:

onStartCommand()Sistemul invocă această metodă prin apelareastartService()atunci când o altă componentă (cum ar fi o activitate) solicită ca serviciul să fie pornit.Când această metodă se execută, serviciul este pornit și poate funcționa în fundal pe termen nelimitat. Dacă implementați această metodă, este responsabilitatea dumneavoastră să opriți serviciul atunci când activitatea sa este terminată prin apelareastopSelf()saustopService(). Dacă doriți doar să furnizați legătura, nu este necesar să implementați această metodă.onBind()Sistemul invocă această metodă prin apelareabindService()atunci când o altă componentă dorește să se lege cu serviciul (de exemplu, pentru a efectua RPC).În implementarea acestei metode, trebuie să furnizați o interfață pe care clienții o folosesc pentru a comunica cu serviciul prin returnarea unuiIBinder. Trebuie să implementați întotdeauna această metodă; cu toate acestea, dacă nu doriți să permiteți legarea, ar trebui să returnaținull.onCreate()Sistemul invocă această metodă pentru a efectua proceduri unice de configurare atunci când serviciul este creat inițial (înainte de a apela fieonStartCommand(), fieonBind()). Dacă serviciul funcționează deja, această metodă nu este apelată.onDestroy()Sistemul invocă această metodă atunci când serviciul nu mai este utilizat și este distrus.Serviciul dvs. ar trebui să implementeze această metodă pentru a curăța toate resursele, cum ar fi firele, ascultătorii înregistrați sau receptorii. Acesta este ultimul apel pe care îl primește serviciul.

Dacă o componentă pornește serviciul prin apelarea startService() (care are ca rezultat un apel la onStartCommand()), serviciul continuă să funcționeze până când se oprește singur cu stopSelf() sau până când o altă componentă îl oprește prin apelarea stopService().

Dacă o componentă apeleazăbindService() pentru a crea serviciul și onStartCommand() nu este apelată, serviciul funcționează doar atât timp cât componenta este legată de el. După ce serviciul este dezlegat de toți clienții săi,sistemul îl distruge.

Sistemul Android oprește un serviciu numai atunci când memoria este scăzută și trebuie să recupereze resursele de sistem pentru activitatea care are accentul utilizatorului. Dacă serviciul este legat de o activitate care are focusul utilizatorului, este mai puțin probabil să fie omorât; dacă serviciul este declarat să ruleze în prim-plan, este rareori omorât.Dacă serviciul este pornit și rulează mult timp, sistemul îi scade poziția în lista de sarcini de fundal în timp, iar serviciul devine foarte susceptibil de a fi omorât – dacă serviciul dvs. este pornit, trebuie să îl proiectați pentru a face față cu grație repornirilor de către sistem. Dacă sistemul vă omoară serviciul, acesta îl repornește imediat ce resursele devin disponibile, dar acest lucru depinde și de valoarea pe care o returnează de la onStartCommand(). Pentru mai multe informațiidespre situațiile în care sistemul ar putea distruge un serviciu, consultați documentul Processes and Threading.

În secțiunile următoare, veți vedea cum puteți crea metodele de serviciustartService() șibindService(), precum și cum să le utilizați din alte componente ale aplicației.

Declararea unui serviciu în manifest

Trebuie să declarați toate serviciile în fișierulmanifest al aplicației dumneavoastră, la fel cum faceți pentru activități și alte componente.

Pentru a vă declara serviciul, adăugați un element <service>ca un copil al elementului <application>. Iată un exemplu:

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

Consultați referința la elementul <service> pentru mai multe informații despre declararea serviciului dvs. în manifest.

Există și alte atribute pe care le puteți include în elementul <service> pentru a defini proprietăți, cum ar fi permisiunile necesare pentru a porni serviciul și procesul în care trebuie să ruleze serviciul. Atributul android:name este singurul atribut obligatoriu – specifică numele clasei serviciului. După ce vă publicați aplicația, lăsați acest nume neschimbat pentru a evita riscul de întrerupere a codului din cauza dependenței de intențiile explicite de a porni sau de a lega serviciul (citiți articolul de pe blog, ThingsThatThat Cannot Change).

Atenție: Pentru a vă asigura că aplicația dvs. este sigură, utilizați întotdeauna o intenție explicită atunci când porniți un Service și nu declarați filtre de intenție pentru serviciile dvs. Utilizarea unei intenții implicite pentru a porni un serviciu reprezintă un pericol pentru securitate deoarece nu puteți fi sigur de serviciul care răspunde la intenție, iar utilizatorul nu poate vedea ce serviciu pornește. Începând cu Android 5.0 (nivel API 21), sistemul aruncă o excepție dacă apelațibindService() cu o intenție implicită.

Vă puteți asigura că serviciul dumneavoastră este disponibil numai pentru aplicația dumneavoastră prinincluderea atributului android:exported și setarea acestuia la false. Acest lucru oprește efectiv alte aplicații să pornească serviciul dumneavoastră, chiar și atunci când folosiți o intenție explicită.

Nota: Utilizatorii pot vedea ce servicii rulează pe dispozitivul lor. Dacă văd un serviciu pe care nu îl recunosc sau în care nu au încredere, ei pot opri serviciul. Pentru a evita ca serviciul dumneavoastră să fie oprit accidental de către utilizatori, trebuie să adăugați atributul android:description la elementul <service> din manifestul aplicației dumneavoastră. În descriere, furnizați o propoziție scurtă care să explice ce face serviciul și ce beneficii oferă.

Crearea unui serviciu pornit

Un serviciu pornit este cel pe care o altă componentă îl pornește prin apelarea startService(), ceea ce are ca rezultat un apel la metodaonStartCommand() a serviciului.

Când un serviciu este pornit, acesta are un ciclu de viață care este independent de componenta care l-a pornit. Serviciul poate funcționa în fundal la nesfârșit, chiar dacă componenta care l-a pornit este distrusă. Ca atare, serviciul ar trebui să se oprească singur atunci când își termină activitatea prin apelarea stopSelf(), sau o altă componentă îl poate opri prin apelarea stopService().

O componentă a aplicației, cum ar fi o activitate, poate porni serviciul prin apelarea startService() și transmiterea unui Intent care specifică serviciul și include orice date pe care serviciul trebuie să le utilizeze. Serviciul primește acest Intent în metoda onStartCommand().

De exemplu, să presupunem că o activitate trebuie să salveze unele date într-o bază de date online. Activitatea poate să pornească un serviciu însoțitor și să-i livreze datele de salvat prin transmiterea unei intenții către startService(). Serviciul primește intenția în onStartCommand(), se conectează la internet și efectuează tranzacția cu baza de date. Când tranzacția este finalizată, serviciul se oprește singur și este distrus.

Atenție: Un serviciu se execută în același proces cu aplicațiaîn care este declarat și în firul principal al acelei aplicații în mod implicit. Dacă serviciul dvs. efectuează operații intensive sau blocante în timp ce utilizatorul interacționează cu o activitate din aceeașiaplicație, serviciul încetinește performanța activității. Pentru a evita impactul asupra performanțelor aplicației, porniți un nou fir de execuție în interiorul serviciului.

Clasa Service este clasa de bază pentru toate serviciile. Atunci când extindeți această clasă, este important să creați un nou fir în care serviciul își poate finaliza toată activitatea; serviciul utilizează în mod implicit firul principal al aplicației dumneavoastră, ceea ce poate încetini performanța oricărei activități pe care o execută aplicația dumneavoastră.

Cadrul Android oferă, de asemenea, subclasa IntentService a Service care utilizează un fir de lucru pentru a gestiona toate cererile de pornire, una câte una. Utilizarea acestei clase nu este recomandată pentru aplicațiile noi, deoarece nu va funcționa bine începând cu Android 8 Oreo, din cauzaintroducerii limitelor de execuție în fundal. în plus, este depreciată începând cu Android 11. Puteți utiliza JobIntentService ca înlocuitor pentru IntentService, care este compatibil cu versiunile mai noi de Android.

Secțiunile următoare descriu modul în care vă puteți implementa propriul serviciu personalizat, cu toate acestea, ar trebui să luați în considerare cu tărie utilizarea WorkManager în schimb pentru majoritatea cazurilor de utilizare. Consultați ghidul pentru procesarea în fundal pe Androidpentru a vedea dacă există o soluție care se potrivește nevoilor dumneavoastră.

Extinderea clasei Service

Puteți extinde clasa Service pentru a gestiona fiecare intenție primită. Iată cum ar putea arăta o implementare de bază:

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

Codul de exemplu gestionează toate apelurile primite în onStartCommand()și postează activitatea într-un Handler care rulează pe un fir de fundal. Acesta funcționează la fel ca un IntentService și procesează toate cererile în serie, una după alta.Ați putea modifica codul pentru a rula lucrarea pe un grup de fire, de exemplu, dacă doriți să executați mai multe cereri simultan.

Rețineți că metoda onStartCommand() trebuie să returneze un număr întreg. Întregul este o valoare care descrie modul în care sistemul ar trebui să continue serviciul în cazul în care sistemul îl omoară. Valoarea de returnare de la onStartCommand() trebuie să fie una dintre următoarele constante:

START_NOT_STICKYDacă sistemul ucide serviciul după ceonStartCommand()returneazăonStartCommand(), nu se recreează serviciul decât dacă mai sunt în așteptare evenimente de livrat. Aceasta este cea mai sigură opțiune pentru a evita rularea serviciului atunci când nu este necesar ș i când aplicația dumneavoastră poate reporni pur ș i simplu orice sarcini neterminate.START_STICKYDacă sistemul ucide serviciul după ceonStartCommand()se întoarce, recreați serviciul și apelaționStartCommand(), dar nu livrați din nou ultima intenție. în schimb, sistemul apeleazăonStartCommand()cu o intenție nulă, cu excepția cazului în care există intenții în așteptare pentru a porni serviciul. În acest caz, aceste intenții sunt transmise. Acest lucru este potrivit pentru playerele media (sau servicii similare) care nu execută comenzi, dar care rulează pe termen nedefinit și așteaptă o sarcină.START_REDELIVER_INTENTDacă sistemul ucide serviciul după ceonStartCommand()se întoarce, recreați serviciul și apelaționStartCommand()cu ultima intenție care a fost livrată serviciului. Orice intenție în așteptare este livrată la rândul ei. Acest lucru este potrivit pentru serviciile care execută în mod activ o sarcină care trebuie reluată imediat, cum ar fi descărcarea unui fișier.

Pentru mai multe detalii despre aceste valori de retur, consultați documentația de referință legată pentru fiecare constantă.

Începerea unui serviciu

Puteți începe un serviciu dintr-o activitate sau altă componentă a aplicației, trecând un Intent la startService() sau startForegroundService(). Sistemul Android apelează metoda onStartCommand() a serviciului și îi transmite Intent, care specifică ce serviciu să pornească.

Notă: Dacă aplicația dvs. vizează nivelul API 26 sau superior, sistemul impune restricții privind utilizarea sau crearea de servicii în fundal, cu excepția cazului în care aplicația însăși se află în prim-plan. Dacă o aplicație trebuie să creeze un serviciu în prim-plan, aceasta trebuie să apeleze startForegroundService(). Această metodă creează un serviciu de fundal, dar metoda semnalează sistemului că serviciul va fi promovat în prim-plan. După ce serviciul a fost creat, acesta trebuie să apeleze metoda startForeground() în termen de cinci secunde.

De exemplu, o activitate poate porni serviciul de exemplu din secțiunea anterioară (HelloService) folosind o intenție explicită cu startService(), așa cum se arată aici:

Kotlin

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

Java

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

Metoda startService()se întoarce imediat, iar sistemul Android apelează metoda onStartCommand() a serviciului. Dacă serviciul nu este deja în funcțiune, sistemul apelează mai întâi onCreate(), iar apoi apelează onStartCommand().

Dacă serviciul nu oferă și o legătură, intenția care este livrată cu startService() este singurul mod de comunicare între componenta aplicației și serviciu. Cu toate acestea, dacă se dorește ca serviciul să trimită un rezultat înapoi, clientul care pornește serviciul poate crea un PendingIntent pentru o difuzare (cu getBroadcast()) și îl poate livra serviciului în Intent care pornește serviciul. Serviciul poate folosi apoi transmisia pentru a livra un rezultat.

Cerințele multiple de pornire a serviciului au ca rezultat mai multe apeluri corespunzătoare la onStartCommand() serviciului. Cu toate acestea, este necesară o singură cerere de oprire a serviciului (cu stopSelf() sau stopService()) pentru a-l opri.

Oprirea unui serviciu

Un serviciu pornit trebuie să își gestioneze propriul ciclu de viață. Adică, sistemul nu se oprește pentru a distruge serviciul decât dacă trebuie să recupereze memoria sistemului, iar serviciul continuă să funcționeze după ce onStartCommand() revine. Serviciul trebuie să se oprească singur prin apelarea stopSelf(), sau o altă componentă îl poate opri prin apelarea stopService().

După ce i se cere să se oprească cu stopSelf() sau stopService(), sistemul distruge serviciul cât mai curând posibil.

Dacă serviciul dvs. gestionează mai multe cereri către onStartCommand() concomitent, nu ar trebui să opriți serviciul atunci când ați terminat de procesat o cerere de pornire, deoarece s-ar putea să fi primit o nouă cerere de pornire (oprirea la sfârșitul primei cereri ar pune capăt celei de-a doua). Pentru a evita această problemă, puteți utiliza stopSelf(int) pentru a vă asigura că cererea de oprire a serviciului se bazează întotdeauna pe cea mai recentă cerere de pornire. Adică, atunci când apelați stopSelf(int), treceți ID-ul cererii de pornire (startId livrat la onStartCommand()) la care corespunde cererea de oprire. Apoi, dacă serviciul primește o nouă cerere de pornire înainte de a putea apela stopSelf(int), ID-ul nu se potrivește și serviciul nu se oprește.

Atenție: Pentru a evita irosirea resurselor sistemului și consumarea energiei bateriei, asigurați-vă că aplicația dvs. își oprește serviciile atunci când a terminat de lucrat.Dacă este necesar, alte componente pot opri serviciul prin apelarea stopService(). Chiar dacă activați legarea pentru serviciu,trebuie întotdeauna să opriți singur serviciul dacă primește vreodată un apel la onStartCommand().

Pentru mai multe informații despre ciclul de viață al unui serviciu, consultați secțiunea de mai jos despre Gestionarea ciclului de viață al unui serviciu.

Crearea unui serviciu legat

Un serviciu legat este unul care permite componentelor aplicației să se lege la el prin apelarea bindService() pentru a crea o conexiune de lungă durată.În general, nu permite componentelor să îl pornească prin apelarea startService().

Crearea unui serviciu legat atunci când doriți să interacționați cu serviciul din activități și alte componente din aplicația dumneavoastră sau să expuneți o parte din funcționalitatea aplicației dumneavoastră altor aplicații prin intermediul comunicării interproces (IPC).

Pentru a crea un serviciu legat, implementați metoda onBind() callback onBind() pentru a returna un IBinder care definește interfața de comunicare cu serviciul. Alte componente ale aplicației pot apela apoi bindService() pentru a prelua interfața și pentru a începe să apeleze metodele serviciului. Serviciul trăiește doar pentru a servi componenta de aplicație care este legată de el, astfel încât atunci când nu mai există componente legate de serviciu, sistemul îl distruge.Nu trebuie să opriți un serviciu legat în același mod în care trebuie să o faceți atunci când serviciul este pornit prin onStartCommand().

Pentru a crea un serviciu legat, trebuie să definiți interfața care specifică modul în care un client poate comunica cu serviciul. Această interfață dintre serviciu ș i client trebuie să fie o implementare a IBinder ș i este ceea ce serviciul dvs. trebuie să returneze din metoda onBind() callback. După ce clientul primește IBinder, acesta poate începe să interacționeze cu serviciul prin intermediul acestei interfețe.

Câțiva clienți se pot lega simultan la serviciu. Când un client a terminat de interacționat cu serviciul, acesta apelează unbindService() pentru a se dezlipi.Când nu mai există clienți legați la serviciu, sistemul distruge serviciul.

Există mai multe moduri de a implementa un serviciu legat, iar implementarea este mai complicată decât un serviciu pornit. Din aceste motive, discuția despre serviciul legat apare într-un document separat despre serviciile legate.

În trimiterea de notificări către utilizator

Când un serviciu este în execuție, acesta poate notifica utilizatorul despre evenimente folosind notificări Toast sau notificări în bara de stare.

O notificare Toast este un mesaj care apare pe suprafața ferestrei curente doar pentru un moment înainte de a dispărea. O notificare a barei de stare oferă o pictogramă în bara de stare cu un mesaj, pe care utilizatorul îl poate selecta pentru a întreprinde o acțiune (cum ar fi începerea unei activități).

De obicei, o notificare a barei de stare este cea mai bună tehnică de utilizat atunci când o activitate de fundal, cum ar fi descărcarea unui fișier, s-a finalizat, iar utilizatorul poate acum să acționeze în consecință. Atunci când utilizatorulselectează notificarea din vizualizarea extinsă, notificarea poate începe o activitate (cum ar fi afișarea fișierului descărcat).

Vezi ghidurile de dezvoltare Toast Notifications sau Status Bar Notificationsdeveloper pentru mai multe informații.

Managementul ciclului de viață al unui serviciu

Ciclul de viață al unui serviciu este mult mai simplu decât cel al unei activități. Cu toate acestea, este chiar mai important să acordați o atenție deosebită modului în care serviciul dvs. este creat și distrus, deoarece un serviciu poate rula în fundal fără ca utilizatorul să fie conștient.

Ciclul de viață al serviciului – de la momentul în care este creat până la cel în care este distrus – poate urma oricare dintre aceste două căi:

  • Un serviciu pornit

    Serviciul este creat atunci când o altă componentă apelează startService(). Serviciul rulează apoi pe termen nedefinit și trebuie să se oprească singur prin apelarea stopSelf(). O altă componentă poate, de asemenea, să oprească acest serviciu prin apelarea stopService(). Atunci când serviciul este oprit, sistemul îl distruge.

  • Un serviciu legat

    Serviciul este creat atunci când o altă componentă (un client) apelează bindService(). Clientul comunică apoi cu serviciulprin intermediul unei interfețe IBinder. Clientul poate închide conexiunea prin apelarea unbindService(). Mai mulți clienți se pot conecta la același serviciu, iar atunci când toți se deconectează, sistemul distruge serviciul. Serviciul nu trebuie să se oprească singur.

Aceste două căi nu sunt complet separate. Vă puteți lega la un serviciu care este deja pornit cu startService(). De exemplu, puteți să porniți un serviciu de muzică de fundal apelând startService() cu un Intent care identifică muzica care trebuie redată. Ulterior, eventual atunci când utilizatorul dorește să exercite un anumit control asupra playerului sau să obțină informații despre melodia în curs, o activitate se poate lega la serviciu prin apelarea bindService(). În astfel de cazuri, stopService() sau stopSelf() nu oprește de fapt serviciul până când toți clienții nu se deblochează.

Implementarea callback-urilor din ciclul de viață

Ca și o activitate, un serviciu are metode de callback din ciclul de viață pe care le puteți implementa pentru a monitoriza modificările în starea serviciului și pentru a efectua activități la momentul potrivit. Următorul skeletonserviciu demonstrează fiecare dintre metodele de apelare a ciclului de viață:

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

Nota: Spre deosebire de metodele de apelare a ciclului de viață ale activităților, nu este necesar să apelați implementarea superclasei acestor metode de apelare.

Figura 2. Ciclul de viață al serviciului. Diagrama din stânga prezintă ciclul de viață atunci când serviciul este creat cu startService(), iar diagrama din dreapta prezintă ciclul de viață atunci când serviciul este creat cu bindService().

Figura 2 ilustrează metodele tipice de callback pentru un serviciu. Deși figura separă serviciile create cu startService() de cele create cu bindService(), rețineți că orice serviciu, indiferent de modul în care este inițiat, poate permite potențial clienților să se lege la el.Un serviciu care a fost inițiat inițial cu onStartCommand() (de către un client care apelează startService()) poate primi în continuare un apel la onBind() (atunci când un client apelează bindService()).

Prin implementarea acestor metode, puteți monitoriza aceste două bucle imbricate ale ciclului de viață al serviciului:

  • Întreaga durată de viață a unui serviciu are loc între momentul în care onCreate() este apelat și momentul în care onDestroy() se întoarce. La fel ca o activitate, un serviciu își face configurarea inițială în onCreate() și eliberează toate resursele rămase în onDestroy(). De exemplu, un serviciu de redare a muzicii poate crea firul în care este redată muzica în onCreate(), iar apoi poate opri firul în onDestroy().

    Nota: Metodele onCreate()și onDestroy() sunt apelate pentru toate serviciile, indiferent dacă sunt create de startService() sau bindService().

  • Viața activă a unui serviciu începe cu un apel fie la onStartCommand(), fie la onBind().Fiecare metodă primește Intent care a fost transmisă fie la startService(), fie la bindService().

    Dacă serviciul este pornit, viața activă se termină în același timp în care se termină întreaga viață (serviciul este încă activ chiar și după ce onStartCommand() se întoarce). În cazul în care serviciul este legat, durata de viață activă se termină atunci când onUnbind() se întoarce.

Nota: Deși un serviciu pornit este oprit printr-un apel fie la stopSelf(), fie la stopService(), nu există un callback respectiv pentru acest serviciu (nu există un callback onStop()). Cu excepția cazului în care serviciul este legat de un client,sistemul îl distruge atunci când serviciul este oprit-onDestroy() este singurul callback primit.

Pentru mai multe informații despre crearea unui serviciu care asigură legarea, consultați documentul Bound Services,care include mai multe informații despre metoda onRebind()callback în secțiunea despre Managing the lifecycle ofa bound service.

Lasă un răspuns

Adresa ta de email nu va fi publicată.