Înțelegerea concordanței pe Android utilizând HaMeR

1. Introducere

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ă: AsyncTaskIntentServiceÎncărcătorAsyncQueryHandler ș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 +.

  • Android de la zero: Operațiuni de fundal

    Filetarea în orice limbă de programare sau platformă este dificilă, iar Android nu face excepție. În acest tutorial veți afla despre unele dintre instrumentele ...
    Paul Trebilcox-Ruiz
    Android SDK
  • Înțelegerea valorilor AsyncTask în 60 de secunde

    Pe Android, clasa AsyncTask este frecvent utilizată pentru a efectua operații pe un fir de fundal. În acest videoclip, vă arăt cum funcționează un AsyncTask și cum ...
    Paul Trebilcox-Ruiz
    Android

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.

2. Responsabilitatea prin intermediul fundalurilor

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 din android.widget și android.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.

3. Cadrul HaMeR

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.

3.1. Clasa Handler

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.

Instanțializarea unui manipulant

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 manipulants. De asemenea, este important să rețineți că: a maieză trebuie să fie activă înainte de asocierea cu a manipulant.

3.2. Looper și MessageQueue

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.

3.3. Pregătirea unui filet pentru HaMeR

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

4. Postarea Runnables

 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 runnables. 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.

5. Trimiterea de mesaje

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 arbitrar
  • Message.arg2: int argument arbitrar
  • Message.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.

5.1. Trimite mesaj() Opțiuni

Similar cu modul în care putem posta runnables, există mai multe opțiuni de trimis Mesajs:

  • 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.

5.2. Manipularea mesajelor cu Handler

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ă; 

6. Concluzie

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.

6.1. Ce urmeaza?

Î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 runnablecu întârzieri. 

Ne vedem în curând!

Cod