Toți cei care încearcă dezvoltarea Android descoperă importanța concurenței. Singura modalitate de a crea o aplicație receptivă este să lăsați subiectul UI cât mai liber posibil, permițând toată munca grea să fie făcută asincron prin fire de fundal.
Datorită designului Android, gestionarea firelor folosind doar java.lang.thread
și java.util.concurrent
pachetele ar putea fi foarte dificile. Folosirea pachetelor de filetare cu nivel scăzut cu Android înseamnă că trebuie să vă faceți griji cu privire la o sincronizare dificilă pentru a evita condițiile de rasă. Din fericire, cei de la Google au făcut munca grea și au construit niște instrumente excelente pentru a ușura munca noastră: AsyncTask
, IntentService
, Încărcător
, AsyncQueryHandler
și CursorLoader
toate sunt utile, precum și clasele HaMeR manipulant
, Mesaj
, și runnable
. Există o mulțime de opțiuni minunate pentru a alege de la, fiecare cu argumentele sale pro și contra.
Au fost spuse multe despre AsyncTask
obiect, și mulți oameni îl folosesc ca pe un glonț de argint soluție pentru concurență pe Android. Este extrem de util pentru operațiunile scurte, ușor de implementat și, probabil, cea mai populară abordare a concurenței pe Android. Dacă doriți să aflați mai multe despre AsyncTask
, verificați următoarele postări Envato Tuts +.
in orice caz, AsyncTask
nu ar trebui să fie singurul instrument pe centura de scule.
Pentru operațiuni pe termen lung, pentru probleme complexe de concurrency sau pentru a obține o mai mare eficiență în anumite situații, ar trebui să alegeți o altă soluție. Dacă aveți nevoie de mai multă flexibilitate sau eficiență decât AsyncTask
oferă, ați putea folosi HaMeR (manipulant
, Mesaj
& runnable
) cadru.În acest tutorial vom explora cadrul HaMeR, unul dintre cele mai puternice modele de concurență disponibile pe Android, și vom afla când și cum să îl folosiți. Într-un tutorial de urmărire, vă voi arăta cum să codificați o aplicație pentru a încerca câteva posibilități ale HaMeR.
Următoarea secțiune va introduce importanța firelor de fundal pentru sistemul Android. Dacă sunteți familiarizat cu acest concept, nu ezitați să îl ignorați și să mergeți direct la discuția despre cadrul HaMeR din secțiunea 3.
Atunci când se pornește o aplicație Android, primul fir provocat de procesul său este firul principal, cunoscut și sub denumirea de fișier UI, care este responsabil de manipularea întregii logici a interfeței utilizator. Acesta este cel mai important fir al unei aplicații. Acesta este responsabil pentru manipularea tuturor interacțiunilor utilizatorilor și, de asemenea, "legarea" pieselor mobile ale aplicației împreună. Android ia acest lucru foarte în serios și, dacă firul tău UI este blocat de lucru pe o sarcină de mai mult de câteva secunde, aplicația se va prăbuși.
[Fișierul UI] este foarte important deoarece este responsabil de expedierea evenimentelor la widget-urile corespunzătoare interfeței utilizator, inclusiv evenimentele desenului. Este, de asemenea, firul în care aplicația dvs. interacționează cu componente din setul de instrumente Android UI (componente dinandroid.widget
șiandroid.view
pachete). Ca atare, firul principal este, de asemenea, uneori numit firul UI. - procese și fire, Android Developer Guide
Problema este că aproape tot codul dintr-o aplicație Android va fi executat în mod implicit pe firul UI. Întrucât sarcinile pe un fir sunt efectuate secvențial, aceasta înseamnă că interfața dvs. de utilizator ar putea "îngheța", devenind nereușită în timp ce procesează unele alte lucrări.
Sarcinile de lungă durată solicitate pe UI vor fi probabil letale pentru aplicația dvs. și va apărea un dialog ANR (Application Not Responding). Chiar și sarcinile mici pot compromite experiența utilizatorului, de aceea abordarea corectă este eliminarea cât mai multor lucruri posibil din UI Thread folosind fire de fundal. Așa cum am spus mai sus, există multe modalități de a rezolva această problemă și vom explora cadrul HaMeR, una dintre soluțiile de bază furnizate de Android pentru a aborda această situație.
Cadrul HaMeR permite thread-urilor de fundal să trimită mesaje sau post-runnables la firul UI și la orice alt thread MessageQueue
prin intermediul manipulatorilor. HaMeR se referă la manipulant
, Mesaj
, & runnable
. Există, de asemenea, câteva alte clase importante care colaborează cu HaMeR: maieză
și MessageQueue
. Împreună, acele obiecte sunt responsabile pentru facilitarea gestionării firului pe Android, având grijă de sincronizare și oferind metode ușoare pentru firele de fundal pentru a comunica cu UI și cu alte fire.
Iată cum se potrivesc clasele din cadrul HaMeR împreună.
maieză
rulează o buclă de mesaje pe un fir folosind MessageQueue
.MessageQueue
conține o listă de mesaje care urmează să fie expediate de către maieză
.manipulant
permite trimiterea și procesarea Mesaj
și runnable
la MessageQueue
. Acesta poate fi folosit pentru a trimite și procesa mesaje între fire.Mesaj
conține o descriere și date care pot fi trimise unui manipulant.runnable
reprezintă o sarcină care trebuie executată.Cu cadrul HaMeR, firele pot trimite mesaje sau obiecte care se pot rula fie la ele, fie la firul UI. HaMeR promovează, de asemenea, interacțiunile filetelor de fundal prin manipulant
.
manipulant
este muncitorul HaMeR. E responsabil de trimiterea Mesaj
(mesaj de date) și postare runnable
(mesaj de sarcină) obiecte către MessageQueue
asociat cu a Fir
. După trimiterea sarcinilor la coadă, manipulatorul primește obiectele de la maieză
și procesează mesajele la momentul potrivit folosind manipulant
asociate cu acesta.
A manipulant
pot fi folosite pentru a trimite sau posta Mesaj
și runnable
obiecte între fire, atâta timp cât astfel de fire au același proces. În caz contrar, va fi necesar să se creeze o comunicare inter-proces (IPC), o metodologie care să depășească scopul acestui tutorial.
A manipulant
trebuie să fie întotdeauna asociată cu o maieză
, iar această conexiune trebuie făcută în timpul instanței sale. Dacă nu oferiți a maieză
la manipulant
, acesta va fi legat de curent Fir
„s maieză
.
// Dispozitivul Handler folosește handler Handler Handler Loader = Thread Handler = new Handler (); // Handler utilizează Looper oferă Handler handler = Handler nou (Looper);
Rețineți că a manipulant
este întotdeauna asociat cu a maieză
, iar această conexiune este permanentă și nu poate fi schimbată odată stabilită. Cu toate acestea, a maieză
firul poate avea asocieri cu multiple manipulant
s. De asemenea, este important să rețineți că: a maieză
trebuie să fie activă înainte de asocierea cu a manipulant
.
Munca de cooperare între maieză
și MessageQueue
într-un fir Java creează o buclă de sarcini care sunt procesate secvențial. O astfel de buclă va menține firul în viață în timp ce așteaptă să primească mai multe sarcini. Un fir poate avea doar unul maieză
și unul MessageQueue
asociate cu acesta; cu toate acestea, pot exista mai mulți manipulatori pentru fiecare fir. Operatorii de procesare sunt responsabili pentru procesarea sarcinilor de pe coadă, iar fiecare sarcină știe care este responsabilul pentru procesarea acesteia.
Interfața de utilizare sau firul principal este singurul tip de fir care, în mod implicit, are deja un a manipulant
, A maieză
, și a MessageQueue
. Alte fire trebuie să fie pregătite cu acele obiecte înainte de a putea lucra cu cadrul HaMeR. În primul rând trebuie să creați o maieză
care include deja o MessageQueue
și atașați-o la fir. Puteți face acest lucru cu o subclasă de Fir
, după cum urmează.
// Pregătirea unui Thread pentru clasa HaMeR LooperThread extinde Thread public Handler mHandler; public void run () // adăugarea și pregătirea Looper.prepare (); // instanța Handler va fi asociată cu loaderul Thread mHandler = new Handler () public void handleMessage (Mesaj msg) // procesează mesajele primite aici; // Pornirea buclă de coadă de mesaje folosind Looper Looper.loop ();
Cu toate acestea, este mai simplu să folosiți o clasă de ajutor numită HandlerThread
, care are a maieză
și a MessageQueue
construit într-o Java Fir
și este gata să primească un Handler.
// Clasa HandlerThread include o clasă publică Looper public HamerThread extinde HandlerThread // trebuie doar să adăugați Handler Handler handler privat; public HamerThread (numele șirului) super (nume);
runnable
este o interfață Java care are multe utilizări. Ar putea fi înțeleasă ca o singură sarcină care trebuie efectuată pe o Fir
. Are o singură metodă care trebuie implementată, Runnable.run ()
, pentru a efectua sarcina.
// Declararea unei Runnable care poate fi executată r = nouă Runnable () @Override public void run () // sarcina merge aici;
Există mai multe opțiuni pentru a posta a runnable
pe o manipulant
.
Handler.post (Runnable r)
: adaugă runnable
la MessageQueue
.Handler.postAtFrontOfQueue (Runnable r)
: adaugă runnable
în partea din față a MessageQueue
.manipulant.postAtTime (Runnable r, long timeMillis)
: adaugă runnable
pe MessageQueue
să fie chemată la un moment dat.manipulant.postDelayed (Runable r, întârziere lungă)
: adaugă runnable
la coada de așteptare după ce a trecut o anumită perioadă de timp.// postarea unui Runnable pe un handler Handler Handler = new Handler (); handler.post (noul Runnable () @Override public void run () // sarcina merge aici);
De asemenea, este posibil să utilizați dispozitivul de tratare UI implicit pentru a posta a runnable
apel Activity.runOnUiThread ()
.
// postarea Runnable folosind Activity Handler UI.runOnUiThread (new Runnable () @Override public void run () / task to perform);
Este important să aveți în vedere unele lucruri runnable
s. Spre deosebire de a Mesaj
, A runnable
nu poate fi reciclată - odată ce treaba sa făcut, este mort. Deoarece face parte dintr-un pachet Java standard, a runnable
nu depinde de manipulant
și poate fi apelat pe un standard Fir
folosind Runnable.run ()
metodă. Cu toate acestea, această abordare nu are nimic de-a face cu cadrul HaMeR și nu va împărți niciunul dintre avantajele sale.
Mesaj
obiect definește un mesaj care conține o descriere și unele date arbitrare care pot fi trimise și procesate prin intermediul manipulant
. Mesaj
este identificat cu un int
definit pe Message.what ()
. Mesaj
pot ține alte două int
argumente și Obiect
pentru a stoca diferite tipuri de date.
Message.what
: int
identificarea Mesaj
Message.arg1
: int
argument arbitrarMessage.arg2
: int
argument arbitrarMessage.obj
: Obiect
pentru a stoca diferite tipuri de date Când trebuie să trimiteți un mesaj, în loc să creați unul de la zero, abordarea recomandată este să extrageți unul reciclat direct din bazinul global cu Message.obtain ()
sau Handler.obtainMessage ()
comenzi. Există câteva versiuni diferite ale acelor metode care vă permit să obțineți o Mesaj
în funcție de necesitățile dvs..
O utilizare obișnuită a Handler.obtainMessage ()
este atunci când trebuie să trimiteți un mesaj către un fir de fundal. Veți folosi manipulant
asociate cu firul respectiv maieză
pentru a obține a Mesaj
și trimiteți-l la firul de fundal, ca în exemplul de mai jos.
int ce = 0; String salut = "Bună ziua!"; // Obținerea mesajului asociat cu fundalul mesajului mesajului msg = handlerBGThread.obtainMessage (ce, salut); // Trimiterea mesajului în fundal Handler pentru fireBGThread.sendMessage (msg);
Există o mulțime de metode reci pe Mesaj
și vă sfătuiesc să examinați mai atent documentația.
Trimite mesaj()
OpțiuniSimilar cu modul în care putem posta runnable
s, există mai multe opțiuni de trimis Mesaj
s:
Handler.sendMessage (Mesaj mesaj)
: adauga o Mesaj
la MessageQueue
.Handler.sendMessageAtFrontOfQueue (Message message)
: adauga o Mesaj
la partea din față a MessageQueue
.Handler.sendMessageAtTime (Mesaj de mesaj, de lungă duratăInMillis)
: adauga o Mesaj
la coada de așteptare la un moment dat.Handler.sendMessageDelayed (Mesaj de mesaj, de lungă duratăInMillis)
: adauga o Mesaj
la coada după o anumită perioadă de timp. Mesaj
obiecte expediate de către maieză
sunt procesate de către manipulant cu metoda Handler.handleMessage
. Tot ce trebuie să faceți este să extindeți manipulant
și suprascrie această metodă pentru a procesa mesajele.
clasa publica MessageHandler extinde Handler @Override public void handleMessage (Mesaj msg) comutare (msg.what) // manipula 'Hello' msg caz 0: String hello = (String) msg.obj; System.out.println (alo); pauză;
Cadrul HaMeR vă poate ajuta să îmbunătățiți codul concurent al aplicației Android. Ar putea părea confuz la început în comparație cu simplitatea unui AsyncTask
, dar deschiderea HaMeR poate fi un avantaj, dacă este utilizat corect.
Tine minte:
Handler.post ()
metode sunt utilizate atunci când expeditorii știu ce operațiuni să efectueze.Handler.sendMessage()
metodele sunt utilizate atunci când receptorul știe ce operație trebuie să efectueze.Pentru a afla mai multe despre filetarea în Android, ar putea fi interesat de cartea Eficient Android Threading: Tehnici de procesare asincronă pentru aplicații Android de Anders Goransson.
În următorul tutorial vom continua să explorăm cadrul HaMeR cu o abordare hands-on, construind o aplicație care demonstrează diferite modalități de utilizare a acestui cadru de concurență Android. Vom crea această aplicație de la bază, încercând diferite posibilități cum ar fi comunicarea între Subiecte
, vorbind cu firul UI, precum și trimiterea de mesaje și postarea runnable
cu întârzieri.
Ne vedem în curând!