Program Android: Procesi, niti i usluge

U ovom vodiču ćemo objasniti kako Android djeluje pri pokretanju usluge, opisat ćemo od čega se sastoje niti izvođenja i o kakvim se procesima radi. To će nam omogućiti razumijevanje načina rada naših aplikacija, dajući nam veću kontrolu i stabilnost na mobilnim uređajima na kojima će biti instalirane.

Nit


Kad korisnik pokrene aplikaciju, Android stvara nit koja se zove main (main). Ova je nit vrlo važna jer je zadužena za upravljanje događajima koje korisnik pokreće u odgovarajućim komponentama, a također uključuje i događaje koji iscrtavaju zaslon. Nit izvršenja, najmanji dio koji može obraditi planer u operativnom sustavu, u ovom slučaju Android (s jezgrom Linuxa).

The implementacija više niti koji se istovremeno obrađuju u istoj aplikaciji, (nazovimo to istodobnost, što se odnosi na istovremenost izvršenja), poznat je kao višenavojni. Multithreading se primjenjuje tako da te niti dijele resurse I to je ono što proces obuhvaća. Zapamtite da se to može programski primijeniti unutar koda iste aplikacije, implementacija višeslojnosti na razini operacijskog sustava ne ovisi o nama.

Početak životnog ciklusa aplikacije uključuje generiranje novog Linux procesa koji je dodijeljen glavnom niti ili korisničkom sučelju (nit koja je odgovorna za grafičku obradu aplikacije, nit korisničkog sučelja na engleskom jeziku).

BilješkaŽivotni ciklus uključuje izvršavanje metoda: onCreate (), onStart () i onResume (); na svom početku i pri njegovom zatvaranju: onPause (), onStop () i onDestroy ().

Android može prisiliti proces da se zatvori zbog nedostatka memorije, ova vrsta slučajeva je rijetka zbog tehnološkog napretka, ali se ipak događa.

Pitanje je: Koje procese Android odlučuje zatvoriti?

Oni se zatvaraju usporedbom njihove važnosti, sažeto je kako slijedi:

Najvažniji: procesi u prvom planuKorisnik stupa u interakciju s navedenim procesom (trenutno je pokrenuta metoda onResume () navedenog procesa). Postoji usluga koja koristi metode svog životnog ciklusa. Ili postoji a BroadcastReceiver vodeći svoje metoda onReceive ().

Drugi najvažniji: Vidljivi procesiAktivnost s pozivom na onPause () metoda. Usluga povezana s vidljivom aktivnošću (vezana usluga).

Treći najvažniji: Proces s uslugomKorisnik ne komunicira izravno s procesom. Proces ima uslugu koja radi u pozadini.

Drugo najmanje važno: Pozadinski procesNe postoji vrsta interakcije s korisnikom. Postupak koji je korisnik posljednji put pogledao bit će posljednji uništen.

Najmanje važno: Prazan procesNema aktivnih sastojaka. Proces je još uvijek živ u svrhu predmemoriranja, sprječavajući korisnika da se vrati na korištenje tog procesa.

Potonji, prazni proces, prvi se prekida u slučaju nedostatka memorije. Stoga će aplikacija koja implementira uslugu u kojoj se stvara nit za preuzimanje sadržaja s interneta biti važnija od aplikacije koja stvara nit bez implementacije usluge, tako da je veća vjerojatnost da će biti prekinuta prije dovršetka preuzimanja. , jer su to dugotrajni procesi.

Da biste razumjeli mulitreading da vidimo kako Android rješava svoju glavnu nit.

PROCES A ima korisničko sučelje ili GLAVNA nit, ova nit obrađuje a red poruka ili red poruka, koji se pokreće dok nit postaje neaktivna, tko to rješava? The Petlja.

Looper je klasa korisničkog sučelja Android Java da, zajedno sa Klasa rukovatelja, obrađuje događaje korisničkog sučelja kao što su pritisci gumba, precrtani zasloni i prekidači za orijentaciju. Događaji se također mogu koristiti za učitavanje sadržaja u HTTP uslugu, promjenu veličine slika i izvršavanje udaljenih zahtjeva. Ključna značajka ovih klasa je da mogu implementirati uzorak istodobnosti.

The Klasa Android Looper sadrži a Red poruka (red poruka) i povezan je samo s temom iz koje je stvoren. Imajte na umu da se ova veza ne može prekinuti i da lLooper ne može se pričvrstiti na bilo koju drugu nit. Također, Looper je na lokalnoj pohrani i može se pozvati samo iz statičke metode. Metoda stupnjevanja provjerava je li Looper već povezan s niti, a zatim statička metoda stvara Looper. Nakon toga, petlja se može koristiti za provjeru poruka u redu.

Zasad razumijemo nekoliko koncepata: proces, nit, nit korisničkog sučelja, petlja, ali još uvijek ne znamo zašto višenavojnost.

Dugotrajno poslovanje


Smatra se dugim za svaku metodu čije izvršavanje prelazi 5 sekundi, što pokreće tipičnu poruku „aplikacija ne reagira. Želite li ga zatvoriti?

Što mogu biti te operacije?: Pristup internetu, SQL upiti, XML / HTML / JSON raščlanjivanje, složena grafička obrada. Bilo koja od ovih operacija koje se izvode u glavnoj niti blokirat će je, a budući da ona upravlja grafičkim korisničkim sučeljem, tumači se kao zamrzavanje, koje android odlučuje zatvoriti.

Zamislimo samo da bilo koja od ovih operacija traje 7 sekundi i korisnik odluči napisati nešto u neki način unosa teksta, pa iako ovih 7 sekundi nije proteklo, nit korisničkog sučelja ne može ažurirati prikaz tako da korisnik cijeni da piše, i pa generira zamrzavanje, pokreće se poruka "bez odgovora" s kojom imate dvije mogućnosti, pričekajte ili uništite, iako nikada ne možete znati koliko dugo čekati, moglo bi potrajati nekoliko sekundi ili čak minuta, ovisno o redu poruka koji imaju glavnu nit.

Kako izbjeći smrzavanje?


Korištenjem niti ili usluga, ovisno o tome zahtijeva li zadatak promjenu prikaza, u ovom slučaju usluga je implementirana jer se pogled aplikacije ne može mijenjati izvan niti korisničkog sučelja. Najbolji način da se izbjegne zamrzavanje je korištenje asinkronih zadataka s klasom AsyncTask, u ovom ćemo vodiču implementirati više niti za razumijevanje ponašanja Android arhitekture.

Kod i razvoj


Projekt koji ćemo sljedeće stvoriti će se temeljiti na preuzimanju slike s kojim moramo stvoriti nit koja nam omogućuje upravljanje pristupom i preuzimanjem putem interneta jer GLAVNI ili Nit korisničkog sučelja ne dopušta ovu radnju.

Počet ćemo stvaranjem novog projekta s praznom aktivnošću, nazvali smo ovaj projekt "Primjer višestruke teme", s jednom jednostavnom aktivnošću stvorit ćemo strukturu XML datoteke koja pripada ovoj djelatnosti.

 
Imamo tekstualno polje, gumb, linearni izgled koji odgovara neodređenoj traci za učitavanje koju ćemo kasnije koristiti i prikaz popisa koji sadrži niz URL -ova slika hostiranih na internetu. U datoteci koja sadrži klasu Java za našu (jedinstvenu) aktivnost zapisana je sljedeća šifra:
 paket com.omglabs.multithreaexample; uvoz android.support.v7.app.AppCompatActivity; uvoz android.os.Bundle; uvoz android.view.View; uvoz android.widget.AdapterView; uvoz android.widget.EditText; uvoz android.widget.LinearLayout; uvoz android.widget.ListView; uvoz android.widget.ProgressBar; javna klasa MainActivity proširuje AppCompatActivity implementira AdapterView.OnItemClickListener {private EditText editText; privatni ListView listView; privatni URL -ovi String []; privatni ProgressBar progressBar; privatni LinearLayout progressLayout; @Override protected void onCreate (Bundle savedInstanceState) {super.onCreate (savedInstanceState); setContentView (R.layout.activity_main); editText = (EditText) findViewById (R.id.downloadURL); listView = (ListView) findViewById (R.id.listurls); listView.setOnItemClickListener (ovo); urls = getResources (). getStringArray (R.array.URLs); progressBar = (ProgressBar) findViewById (R.id.progressbar); progressLayout = (LinearLayout) findViewById (R.id.progresslayout); } preuzimanje javne praznine (prikaz View) {} @Override public void onItemClick (AdapterView adapterView, View view, int i, long l) {editText.setText (urlovi [i]); }} 
Do sada se aplikacija mogla sastaviti bez ikakvih problema, u ovoj klasi deklariramo varijable:
  • editText
  • listView
  • URL -ovi
  • traka za napredak
  • progressLayout

Tekstualno polje, popis, raspored niza, traka napretka i linearni izgled.

U metoda onCreate Njima dodjeljujemo odgovarajući prikaz koji im pripada i koji su stvoreni u XML datoteci aktivnosti, s izuzetkom URL -ova koji dodjeljuju svoje vrijednosti iz mape vrijednosti u datoteci niza i čiji je raspored deklariran kako slijedi:

 http://www.fmdos.cl/wp-content/uploads/2016/03/1.jpg.webp http://vignette3.wikia.nocookie.net/teenwolf/images/9/90/Crystal_Reed_003.jpeg.webp https: // pbs.twimg.com/profile_images/699667844129107968/EvhTFBHN.jpg.webp http://vignette1.wikia.nocookie.net/teen-wolf-pack/images/0/0b/Holland-holland-roden-31699868-500-600.png.webp 
Prazna metoda preuzimanja (prikaz View) bit će ispunjena kodom koji će izvršiti preuzimanje i koji je povezan s Gumb za preuzimanje Bot putem atributa onclick. Konačno metoda onitemclick koji pripada prikaz liste, ispunjava tekstualno polje kada kliknete na bilo koji url koji se nalazi na popisu. Nakon sastavljanja ovaj kod će izgledati ovako:

U sljedećem koraku stvorit ćemo metode koje će prijeći na preuzimanje, slijedeći ove korake:

  • Izradite objekt klase URL -a (java.net) koji će predstavljati url za preuzimanje.
  • Otvorite vezu pomoću tog objekta.
  • Očitajte podatke (putem weba) pomoću klase ulaznog toka u nizu bajtova.
  • Otvorite / stvorite datoteku izlaznog toka u kojoj će se url podaci spremati na SD karticu.
  • Zapišite podatke u tu datoteku.
  • I na kraju prekinite vezu.

Za sada će to izgledati ovako:

 javno logičko preuzimanje pomoćuThreads (veza niza) {boolean confirmation = false; URL downloadLink = null; HttpURLConnection conne = null; InputStream inputStream = null; pokušajte {downloadLink = novi URL (veza); veza = (HttpURLConnection) downloadLink.openConnection (); inputStream = conne.getInputStream (); } catch (MalformedURLException e) {e.printStackTrace (); } catch (IOException e) {e.printStackTrace (); } konačno {if (connex! = null) {connex.disconnect (); } if (inputStream! = null) {try {inputStream.close (); } catch (IOException e) {e.printStackTrace (); }}} potvrda povrata; } 
Ova metoda koju smo izgradili trebat će samo Niz koji će biti URL za preuzimanje, jest boolean Za potvrdu preuzimanja, downloadLink je URL objekt, veza je veza koja će se uspostaviti za pristup objektu, a inputStream je ona koja će nastaviti čitati podatke, ako pokušamo koristiti ovu metodu na gumbu downloadBot aplikacija bi se zaustavila zbog nemogućnosti pokretanja na glavna nit.

Ovdje idemo s upotrebom niti, postoje dva načina da to učinite s klasom, a to je proširivanjem te klase na Thread ili implementacijom klase Runnable, ova klasa nije nit koja vam jednostavno omogućuje stvaranje metode koju može pokrenuti u određenom trenutku, a ako stvorite zasebnu nit, pokrenite je u njoj.

Unutar gumba za preuzimanje napisat ćemo ovaj kôd koji će izgledati ovako:

 javno preuzimanje praznine (prikaz) {Thread mThread = nova nit (nova mRunn ()); mThread.start (); } 
Ovdje stvaramo novu nit kojoj je potreban Runnable objekt koji stvaramo u privatnoj klasi poput ove:
 privatna klasa mRunn implementira Runnable {@Override public void run () {download usingThreads (urls [0]); }} 
Napravite privatnu klasu

BilješkaUpamtite da je to sve u klasi Java naše jedine aktivnosti.

Sa crtom:

 preuzimanje pomoćuTreads (url [0]);
Pozivamo funkciju koju smo stvorili tamo gdje smo otvorili vezu, stavka URL niza joj se prosljeđuje kako bi mogla čitati podatke s te adrese. Kasnije će biti izmijenjen.

Ako bismo pokušali pokrenuti ovu aplikaciju pritiskom na gumb, aplikacija bi se zaustavila, jer nam je potrebno posebno dopuštenje za pristup internetu, što se traži kroz manifest naše aplikacije. Dodavanje retka ispred oznake:

 
Sada ćemo provjeriti izvršava li aplikacija preuzimanje te datoteke, dodat ćemo nekoliko redaka koda u način preuzimanja usingThreads, to će izgledati ovako:
 javno booleansko preuzimanje usingThreads (veza niza) {boolean confirmation = false; URL downloadLink = null; HttpURLConnection conne = null; InputStream inputStream = null; FileOutputStream archOutputStream = null; Datoteka datoteka = null; pokušajte {downloadLink = novi URL (veza); veza = (HttpURLConnection) downloadLink.openConnection (); inputStream = conne.getInputStream (); datoteka = nova datoteka (Environment.getExternalStoragePublicDirectory (Environment.DIRECTORY_DOWNLOADS) + "/" + Uri.parse (veza) .getLastPathSegment ()); archOutputStream = novi FileOutputStream (datoteka); int Čitanje = -1; bajt [] međuspremnik = novi bajt [1024]; while ((Čitanje = inputStream.read (međuspremnik))! = -1) {archOutputStream.write (međuspremnik, 0, čitanje); } potvrda = istina; } catch (MalformedURLException e) {e.printStackTrace (); } catch (IOException e) {e.printStackTrace (); } konačno {if (connex! = null) {connex.disconnect (); } if (inputStream! = null) {try {inputStream.close (); } catch (IOException e) {e.printStackTrace (); }} if (archOutputStream! = null) {try {archOutputStream.close (); } catch (IOException e) {e.printStackTrace (); }}} potvrda povrata; } FileOutputStream archOutputStream = null; Datoteka datoteka = null; 
Deklaracije ovih objekata predstavljaju pisanje datoteke koja se čita i praznu datoteku u koju će se čitanje spremiti.
 datoteka = nova datoteka (Environment.getExternalStoragePublicDirectory (Environment.DIRECTORY_DOWNLOADS) + "/" + Uri.parse (urls [0]). getLastPathSegment ()); archOutputStream = novi FileOutputStream (datoteka); int Čitanje = -1; bajt [] međuspremnik = novi bajt [1024]; while ((Čitanje = inputStream.read (međuspremnik))! = -1) {archOutputStream.write (međuspremnik, 0, čitanje); } potvrda = istina; 
"Datoteka" je prazan objekt Datoteka čija je adresa izgrađena pristupom SD kartici "Environment.getExternalStoragePublicDirectory (Environment.DIRECTORY_DOWNLOADS)" i dodavanjem kose crte "/" i posljednjeg segmenta URL -a koji općenito predstavlja naziv datoteke u preuzimanjem, to postižemo metodom getLastPathSegment ().

Prije testiranja aplikacije dodat ćemo posljednje dopuštenje u manifest:

 
Nakon pokretanja aplikacije na emulatoru ili Android uređaju, pritiskom na gumb vidjet ćemo da se očito ništa ne događa, no ako provjerimo mapu Preuzmi istraživačem datoteka shvatit ćemo da je prva stavka na popisu preuzeta; fotografija koja se zove 1.jpg.webp.

Da biste to učinili dinamičku aplikaciju i implementirati URL -ove prikaza liste, ažurirat ćemo način preuzimanja (prikaz) i ovo ćemo dodati, kao prvi redak:

 Veza niza = editText.getText (). ToString ();
I u klasa mRunn ovo ćemo dodati prije metode run ():
 privatna klasa mRunn implementira Runnable {private String link; javni mRunn (String veza) {this.link = veza; } @Override public void run () {download usingThreads (link); }}
I u klasa mRunn ovo ćemo dodati prije metode run ():

Tako možemo varijablu veze prenijeti iz tekstualnog polja u metodu koja izvodi preuzimanje. Aplikacija je u ovom trenutku potpuno funkcionalna, iako joj nedostaje malo prilagođenosti korisnicima, pa ćemo to pokušati popraviti, koristeći traku napretka koju smo naveli na početku.

U klasu mRunn u metodu run () uključit ćemo:

 MainActivity.this.runOnUiThread (novi Runnable () {@Override public void run () {progressLayout.setVisibility (View.VISIBLE);}}); 
Prije poziva na downloadusandoThreads. Time će se traka za učitavanje pojaviti kada pritisnemo gumb, u konačnoj klauzuli datoteke način preuzimanja usingThreads.

Dodat ćemo:

 this.runOnUiThread (novi Runnable () {@Override public void run () {progressLayout.setVisibility (View.GONE);}}); 
Dakle, kad je preuzimanje dovršeno, traka ponovno nestaje. To će se dogoditi bez obzira na to je li preuzimanje uspješno.
I ovo je bilo sve, jedno kratka implementacija više nitiOvo je pomalo dosadno i donosi neke komplikacije za složenije aplikacije.Najučinkovitiji način za postizanje ovog zadatka, u našem slučaju preuzimanje nekih slika, je korištenje AsyncTasks.

wave wave wave wave wave