În acest tutorial vom explora Serviciu
componentă și superclase sale, IntentService
. Veți afla când și cum să utilizați această componentă pentru a crea soluții de concurrency excelente pentru operațiile de fundal de lungă durată. De asemenea, vom analiza rapid IPC (Inter Process Communication), pentru a învăța cum să comunicați cu serviciile care rulează pe diferite procese.
Pentru a urma acest tutorial, veți avea nevoie de o înțelegere a concurenței pe Android. Dacă nu știți prea multe despre asta, ați putea dori să citiți mai întâi unele dintre celelalte articole despre acest subiect.
Serviciu
componenta este o parte foarte importantă a cadrului concurenței Android. Acesta îndeplinește necesitatea de a efectua o operațiune de lungă durată în cadrul unei aplicații sau oferă anumite funcționalități pentru alte aplicații. În acest tutorial ne vom concentra exclusiv pe Serviciu
de lungă durată și capacitatea de a folosi această putere pentru a îmbunătăți concurența.
A Serviciu
este o componentă simplă, care este instanțiată de sistem pentru a efectua o activitate de lungă durată care nu depinde în mod necesar de interacțiunea utilizatorului. Aceasta poate fi independentă de ciclul de viață al activității și poate, de asemenea, să se desfășoare într-un proces complet diferit.
Înainte de a scufunda într-o discuție despre ce a Serviciu
reprezintă, este important să subliniem că, deși serviciile sunt utilizate în mod obișnuit pentru operațiunile de fundal de lungă durată și pentru a executa sarcini pe diferite procese, A Serviciu
nu reprezintă a Fir
sau un proces. Acesta se va executa numai într-un fir de fundal sau într-un proces diferit, dacă este explicit solicitat să facă acest lucru.
A Serviciu
are două caracteristici principale:
Există o mulțime de confuzii cu privire la servicii și fire. Când un Serviciu
este declarat, nu conține a Fir
. De fapt, în mod implicit, rulează direct pe firul principal și orice lucrare efectuată pe acesta poate îngheța o aplicație. (Cu excepția cazului în care este a IntentService
, A Serviciu
subclasa care vine deja cu un thread de lucrător configurat.)
Deci, cum oferă serviciile o soluție de concurență? Ei bine, a Serviciu
nu conține în mod implicit un fir, dar poate fi ușor configurat pentru a lucra cu firul propriu sau cu o mulțime de fire. Vom vedea mai multe despre asta mai jos.
Dacă nu luați în considerare lipsa unui fir încorporat, a Serviciu
este o soluție excelentă pentru problemele de concurență în anumite situații. Principalele motive pentru a alege o Serviciu
peste alte soluții de concurență cum ar fi AsyncTask
sau cadrul HaMeR sunt:
Serviciu
poate fi independent de ciclurile de viață ale activității.Serviciu
este adecvată pentru derularea operațiunilor lungi.Serviciu
poate fi repornit pentru a-și relua activitatea.Există două tipuri de Serviciu
, a început și legat.
A a început serviciul este lansat prin Context.startService ()
. În general, acesta efectuează o singură operație și va funcționa pe termen nelimitat până la terminarea operațiunii, apoi se închide. În mod normal, acesta nu returnează niciun rezultat interfeței cu utilizatorul.
legat de serviciu este lansat prin Context.bindService ()
, și permite o comunicare bidirecțională între client și client Serviciu
. De asemenea, se poate conecta cu mai mulți clienți. Se distruge atunci când nu există niciun client conectat la el.
Pentru a alege între cele două tipuri, Serviciu
trebuie să pună în aplicare câteva apeluri de apel: onStartCommand ()
pentru a rula ca serviciu început, și onBind ()
pentru a rula ca serviciu limitat. A Serviciu
poate alege să implementeze doar unul dintre aceste tipuri, dar poate adopta ambele în același timp fără probleme.
Pentru a utiliza un serviciu, extindeți Serviciu
și suprascrie metodele de apel invers, în funcție de tipul de Serviciu
. Așa cum am menționat anterior, pentru serviciile începute onStartCommand ()
trebuie aplicată metoda și pentru serviciile obligatorii, onBind ()
metodă. De fapt, onBind ()
metoda trebuie declarată pentru fiecare tip de serviciu, dar poate reveni la nul pentru serviciile pornite.
clasa publica CustomService extinde serviciul @Override public int onStartCommand (Intent intent, int flags, int startId) // Executa operatiunile dumneavoastra // Serviciul nu va fi incheiat automat returneaza Service.START_NOT_STICKY; @Nullable @Override publice IBinder onBind (Intent intent) // Creează o conexiune cu un client // utilizând o interfață implementată la IBinder return null;
onStartCommand ()
: lansat de Context.startService ()
. Acest lucru este de obicei chemat dintr-o activitate. Odată ce ați sunat, serviciul se poate desfășura pe o perioadă nedeterminată și depinde de dvs. să îl opriți, fie prin apel stopSelf ()
sau stopService ()
.onBind ()
: apelat când o componentă dorește să se conecteze la serviciu. Chemat pe sistem de către Context.bindService ()
. Se întoarce IBinder
care oferă o interfață pentru a comunica cu clientul.Ciclul de viață al serviciului este de asemenea important să fie luat în considerare. onCreate ()
și onDestroy ()
ar trebui implementate metode de inițializare și închidere a oricăror resurse sau operațiuni ale serviciului.
Serviciu
componentă trebuie să fie declarată pe manifest cu
element. În această declarație este posibil, dar nu obligatoriu, să se stabilească un alt proces pentru Serviciu
a alerga în.
... ...
Pentru a iniția un serviciu început, trebuie să apelați Context.startService ()
metodă. scop
trebuie să fie create cu Context
si Serviciu
clasă. Orice informație sau date relevante trebuie să fie transmise și în acest sens scop
.
Intent serviceIntent = intenție nouă (acest lucru, CustomService.class); // Transmiterea datelor care urmează a fi procesate pe datele pachetului de servicii = nou pachet (); data.putInt ("Tip de operare", 99); data.putString ("DownloadURL", "http://mydownloadurl.com"); serviceIntent.putExtras (date); // Pornirea serviciului startService (serviceIntent);
În dvs. Serviciu
clasă, metoda pe care ar trebui să o faceți este onStartCommand ()
. În această metodă, trebuie să apelați orice operație pe care doriți să o executați la serviciul inițiat. Veți procesa scop
pentru a capta informațiile trimise de client. startId
reprezintă un ID unic, creat automat pentru această cerere specifică și steaguri
poate conține informații suplimentare despre el.
@Override public int peStartCommand (Intent intent, int flags, int startId) Bundle data = intent.getExtras (); dacă (date! = null) int operație = data.getInt (KEY_OPERATION); // Verificați ce operație să efectuați și trimiteți un msg dacă (operație == OP_DOWNLOAD) // efectuați descărcarea returnați START_STICKY;
onStartCommand ()
returnează o constantă int
care controlează comportamentul:
Service.START_STICKY
: Serviciul este repornit dacă se termină.Service.START_NOT_STICKY
: Serviciul nu este repornit.Service.START_REDELIVER_INTENT
: Serviciul este repornit după un accident și intențiile de prelucrare vor fi redeschise.După cum am menționat mai sus, serviciul inițiat trebuie oprit, altfel acesta va dura nelimitat. Acest lucru se poate face fie de către Serviciu
apel stopSelf ()
pe sine sau prin apelul unui client stopService ()
pe el.
void someOperation () // efectuați o operație de lungă durată // și opriți serviciul atunci când este terminat stopSelf ();
Componentele pot crea conexiuni cu serviciile, stabilind o comunicare bidirecțională cu aceștia. Clientul trebuie să sune Context.bindService ()
, trecerea unui scop
, A ServiceConnection
interfață și a steag
ca parametri. A Serviciu
poate fi legat la mai mulți clienți și va fi distrusă odată ce nu are clienți conectați la acesta.
void bindWithService () Intent intent = intenție nouă (aceasta, PlayerService.class); // obligați cu Service bindService (intent, mConnection, Context.BIND_AUTO_CREATE);
Este posibil să trimiteți Mesaj
obiecte pentru servicii. Pentru a face acest lucru va trebui să creați o Mesager
pe partea clientului într-un ServiceConnection.onServiceConnected
implementarea interfeței și folosiți-o pentru a trimite Mesaj
obiecte la Serviciu
.
private ServiceConnection mConnection = nou ServiceConnection () @Override public void onServiceConnected (ComponentName className, serviciul IBinder) // utilizați IBinder-ul primit pentru a crea un Messenger mServiceMessenger = nou Messenger (serviciu); mBound = adevărat; @Override publice void onServiceDisconnected (ComponentName arg0) mBound = false; mServiceMessenger = null; ;
De asemenea, este posibil să transmiteți un răspuns Mesager
la Serviciu
pentru ca clientul să primească mesaje. Ferește-te, totuși, pentru că clientul nu mai este în jur pentru a primi mesajul serviciului. Ați putea, de asemenea, să utilizați BroadcastReceiver
sau orice altă soluție difuzată.
managerul privat mResponseHandler = manipulator nou () @Override public void handleMessage (Mesaj mesaj) // răspunsul mânerului de la Serviciu; Mesaj msgReply = Message.obtain (); msgReply.replyTo = Messenger nou (mResponseHandler); încercați mServiceMessenger.send (msgReply); captură (RemoteException e) e.printStackTrace ();
Este important să dezactivați Serviciul când clientul este distrus.
@Override protejate void onDestroy () super.onDestroy (); // deconectați de la serviciu dacă (mBound) unbindService (mConnection); mBound = false;
Pe Serviciu
parte, trebuie să pună în aplicare Service.onBind ()
metoda, oferind un IBinder
furnizate de la Mesager
. Aceasta va transmite un răspuns manipulant
să se ocupe de Mesaj
obiecte primite de la client.
IncomingHandler (PlayerService playerService) mPlayerService = new WeakReference <> (playerService); @Override public void handleMessage (Mesaj mesaj) // mesaje de manipulare public IBinder onBind (intent intent) // a trece un Binder folosind Messenger creat întoarcere mMessenger.getBinder (); final Messenger mMessenger = Messenger nou (noul IncomingHandler (acest));
În cele din urmă, este timpul să vorbim despre cum să rezolvăm problemele de concurrency folosind serviciile. După cum am menționat mai devreme, un standard Serviciu
nu conține nicio extra fire și va rula pe principalele Fir
în mod implicit. Pentru a depăși această problemă, trebuie să adăugați un lucrător Fir
, o mulțime de fire sau executați Serviciu
pe un alt proces. Ați putea folosi și o subclasă de Serviciu
denumit IntentService
care conține deja a Fir
.
Pentru a face Serviciu
executați pe fundal Fir
ai putea crea doar un extra Fir
și conduceți slujba acolo. Cu toate acestea, Android ne oferă o soluție mai bună. O modalitate de a profita cât mai bine de sistem este implementarea cadrului HaMeR în interiorul sistemului Serviciu
, de exemplu prin looparea a Fir
cu o coadă de mesaje care poate procesa mesaje pe termen nelimitat.
Este important să înțelegeți că această implementare va procesa secvențial sarcinile. Dacă trebuie să primiți și să procesați mai multe sarcini în același timp, ar trebui să utilizați o mulțime de fire. Folosirea piscinelor de filete nu face parte din acest tutorial și nu vom mai vorbi astăzi.
Pentru a utiliza HaMeR trebuie să furnizați Serviciu
cu maieză
, A manipulant
și a HandlerThread
.
Looper privat mServiceLooper; privat ServiceHandler mServiceHandler; // Handler pentru a primi mesaje de la clasa finală privată client ServiceHandler extinde Handler ServiceHandler (looper looper) super (looper); @Override public void handleMessage (Mesaj msg) super.handleMessage (msg); // gestionarea mesajelor // oprirea serviciului folosind oprirea startId stopSelf (msg.arg1); @Override public void onCreate () HandlerThread thread = noul HandlerThread ("ServiceThread", Process.THREAD_PRIORITY_BACKGROUND); thread.start (); mServiceLooper = thread.getLooper (); mServiceHandler = nou serviciuHandler (mServiceLooper);
În cazul în care cadrul HaMeR nu vă este cunoscut, citiți tutorialele noastre despre concursul HaMer pentru Android.
Dacă nu este nevoie de Serviciu
pentru a fi păstrat viu pentru o lungă perioadă de timp, ați putea folosi IntentService
, A Serviciu
subclasa care este gata să execute sarcini pe fire de fundal. Intern, IntentService
este a Serviciu
cu o implementare foarte asemănătoare cu cea propusă mai sus.
Pentru a utiliza această clasă, tot ce trebuie să faceți este extinderea acesteia și implementarea acesteia onHandleIntent ()
, o metodă de cârlig care va fi apelată de fiecare dată când un client solicită startService ()
pe aceasta Serviciu
. Este important să rețineți că IntentService
se va opri de îndată ce se termină activitatea.
clasa publica MyIntentService extinde IntentService public MyIntentService () super ("MyIntentService"); @Override protejat void onHandleIntent (Intent intent) // handle Intents trimite prin startService
A Serviciu
poate rula pe un complet diferit Proces
, independent de toate sarcinile care se întâmplă în procesul principal. Un proces are propria sa alocare de memorie, grup de fire și priorități de procesare. Această abordare poate fi foarte utilă atunci când trebuie să lucrați independent de procesul principal.
Comunicarea între diferitele procese se numește IPC (Inter Process Communication). Într-un Serviciu
există două modalități principale de a face IPC: folosind a Mesager
sau implementarea unui AIDL
interfață.
Am învățat cum să trimiteți și să primiți mesaje între servicii. Tot ce trebuie să faceți este să utilizați creați un Mesager
folosind IBinder
instanță primită în timpul procesului de conectare și folosiți-o pentru a trimite un răspuns Mesager
înapoi la Serviciu
.
managerul privat mResponseHandler = manipulator nou () @Override public void handleMessage (Mesaj mesaj) // răspunsul mânerului de la Serviciu; private ServiceConnection mConnection = nou ServiceConnection () @Override public void onServiceConnected (ComponentName className, serviciul IBinder) // utilizați IBinder-ul primit pentru a crea un Messenger mServiceMessenger = nou Messenger (serviciu); Mesaj msgReply = Message.obtain (); msgReply.replyTo = Messenger nou (mResponseHandler); încercați mServiceMessenger.send (msgReply); captură (RemoteException e) e.printStackTrace ();
AIDL
interfața este o soluție foarte puternică care permite apeluri directe Serviciu
metodele care rulează pe diferite procese și este potrivit să se utilizeze atunci când dvs. Serviciu
este într-adevăr complexă. in orice caz, AIDL
este complicat să se implementeze și este rar folosit, astfel încât utilizarea sa nu va fi discutată în acest tutorial.
Serviciile pot fi simple sau complexe. Depinde de nevoile aplicației dvs. Am încercat să acoperez cât mai mult posibil pe acest tutorial, totuși m-am concentrat doar pe utilizarea serviciilor în scopuri concurente și există mai multe posibilități pentru această componentă. Vreau să studiez mai mult, să aruncăm o privire la ghidul de documentație și Android.
Ne vedem în curând!