I denne opplæringen vil vi forklare hvordan Android fungerer når du kjører en tjeneste, vil vi beskrive hva kjøringstrådene består av og hva prosessene handler om. Dette vil tillate oss å forstå måten applikasjonene våre kjøres på, noe som gir oss større kontroll og stabilitet på de mobile enhetene der de skal installeres.
Tråd
Når brukeren kjører et program, Android lager en tråd kalt main (main). Denne tråden er veldig viktig fordi den har ansvaret for å administrere hendelsene som brukeren utløser til de riktige komponentene, og inkluderer også hendelsene som tegner skjermen. En kjøringstråd, den minste delen som kan behandles av en planlegger i et operativsystem, i dette tilfellet Android (med Linux -kjerne).
De implementering av flere tråder som behandles samtidig i samme applikasjon, (kall det samtidighet, som refererer til samtidig utførelse), det er kjent som multithreading. Multithreading brukes slik at disse trådene deler ressurser Og dette er hva en prosess består av, husk at dette kan brukes programmatisk innenfor koden til den samme applikasjonen, implementeringen av multithreading på operativsystemnivå er ikke avhengig av oss.
Begynnelsen på livssyklusen til et program inkluderer generering av en ny Linux -prosess som er tilordnet en hovedtråd eller UI -tråd (tråden som er ansvarlig for den grafiske behandlingen av applikasjonen, brukergrensesnitttråd på engelsk).
MerkLivssyklusen inkluderer utførelse av metodene: onCreate (), onStart () og onResume (); ved starten og ved avslutningen: onPause (), onStop () og onDestroy ().
En prosess kan bli tvunget til å lukke av Android på grunn av mangel på minne. Denne typen saker er sjelden på grunn av teknologiske fremskritt, men det skjer fortsatt.
Spørsmålet er: Hvilke prosesser bestemmer Android seg for å lukke?
Disse lukkes ved å sammenligne deres viktighetsnivå, det er oppsummert som følger:
Det viktigste: forgrunnsprosesserBrukeren samhandler med prosessen (onResume () -metoden for prosessen kjører for øyeblikket). Det er en tjeneste som kjører sine livssyklusmetoder. Eller er det en Kringkastermottaker kjører hans onReceive () metode.
Den nest viktigste: Synlige prosesserAktivitet med oppringning til onPause () -metode. Tjeneste knyttet til en synlig aktivitet (bundet tjeneste).
Den tredje viktigste: Prosess med en tjenesteBrukeren samhandler ikke direkte med prosessen. Prosessen har en tjeneste som kjører i bakgrunnen.
Den nest minst viktige: BakgrunnsprosessDet er ingen form for interaksjon med brukeren. Prosessen som sist ble sett av brukeren vil være den siste som blir ødelagt.
Det minst viktige: Tom prosessDen har ingen aktive komponenter. Prosessen lever fortsatt for hurtigbufringsformål, og forhindrer brukeren i å gå tilbake til bruk av denne prosessen.
Sistnevnte, den tomme prosessen, er den første som avsluttes ved mangel på hukommelse. Dermed vil en applikasjon som implementerer en tjeneste der det opprettes en tråd for å laste ned innhold fra internett, være viktigere enn en applikasjon som oppretter tråden uten å implementere en tjeneste, slik at det er mer sannsynlig å bli avsluttet før nedlasting er fullført. , fordi de er langvarige prosesser.
For å forstå multhreading la oss se hvordan Android håndterer hovedtråden.
PROSESS A har et brukergrensesnitt eller Hovedtråd, denne tråden håndterer a meldingskø eller meldingskø, som går når tråden blir inaktiv, hvem håndterer dette? De Looper.
Looper er en brukergrensesnittklasse på Android Java det, sammen med Handler klasse, behandler hendelser i brukergrensesnittet som knappetrykk, tegninger på nytt og orienteringsbrytere. Hendelser kan også brukes til å laste innhold til en HTTP -tjeneste, endre størrelse på bilder og utføre eksterne forespørsler. Hovedtrekk ved disse klassene er at de er i stand til å implementere et samtidighetsmønster.
De Android Looper -klasse inneholder en MessageQueue (meldingskø) og er bare knyttet til emnet den ble opprettet fra. Vær oppmerksom på at denne tilkoblingen ikke kan brytes, og at lLooper den kan ikke festes til noen annen tråd. Looper er også på lokal lagring og kan bare ringes fra en statisk metode. En iscenesettelsesmetode sjekker om en Looper allerede er knyttet til en tråd, og deretter oppretter den statiske metoden Looper. Etterpå kan en loop brukes til å kontrollere meldingene i køen.
Så langt forstår vi flere begreper: prosess, tråd, UI -tråd, looper, men vi vet fortsatt ikke hvorfor multithreading.
Langsiktig drift
Det regnes som lang varighet for enhver metode hvis utførelse overstiger 5 sekunder, noe som utløser den typiske meldingen "programmet reagerer ikke. Vil du lukke den?
Hva kan disse operasjonene være?: Internett -tilgang, SQL -spørringer, XML / HTML / JSON -analyse, kompleks grafikkbehandling. Enhver av disse operasjonene som kjøres i hovedtråden vil blokkere den, og siden det er den som håndterer det grafiske brukergrensesnittet, blir det tolket som en fryse, som android bestemmer seg for å lukke.
La oss bare forestille oss at noen av disse operasjonene varer i 7 sekunder og brukeren bestemmer seg for å skrive noe i tekstinndata, så selv om disse 7 sekundene ikke har gått, kan ikke UI -tråden oppdatere visningen slik at brukeren setter pris på at han skriver, og så det genererer en frysing, "ingen svar" -meldingen utløses som du har to alternativer med, vent eller ødelegg, selv om du aldri kan vite hvor lenge du skal vente, kan det være noen sekunder eller minutter, avhengig av meldingskøen som har hovedtråden.
Hvordan unngår vi å fryse?
Bruk av tråder eller tjenester, avhengig av om oppgaven krever endring av visningen, i dette tilfellet er en tjeneste implementert fordi visningen av et program ikke kan endres utenfor UI -tråden. Den beste måten å unngå frysing er å bruke asynkrone oppgaver med AsyncTask -klassen. I denne opplæringen vil vi implementere flere tråder for å forstå oppførselen til Android -arkitekturen.
Kode og utvikling
Prosjektet som vi skal lage neste vil være basert på en nedlasting av bilder som vi må lage en tråd som lar oss administrere tilgang og nedlasting over internett fordi HOVED eller UI -tråd tillater ikke denne handlingen.
Vi starter med å lage et nytt prosjekt med en tom aktivitet, vi har kalt dette prosjektet "MultiThreadExample", med en enkel aktivitet vi vil lage strukturen til XML -filen som tilhører denne aktiviteten.
Vi har et tekstfelt, en knapp, en lineær layout som tilsvarer en ubestemt lastelinje som vi skal bruke senere, og en listevisning som inneholder en rekke URL -er for bilder som er lagret på internett. I filen som inneholder Java -klassen for vår (unike) aktivitet, er den skrevet med følgende kode:
pakke com.omglabs.multithreaexample; importer android.support.v7.app.AppCompatActivity; importer android.os.Bundle; importer android.view.View; importer android.widget.AdapterView; importer android.widget.EditText; importer android.widget.LinearLayout; importer android.widget.ListView; importer android.widget.ProgressBar; public class MainActivity utvider AppCompatActivity implementerer AdapterView.OnItemClickListener {private EditText editText; private ListView listView; private String [] urls; private ProgressBar progressBar; private LinearLayout progressLayout; @Override protected void onCreate (Bundle savedInstanceState) {super.onCreate (saveInstanceState); setContentView (R.layout.activity_main); editText = (EditText) findViewById (R.id.downloadURL); listView = (ListView) findViewById (R.id.listurls); listView.setOnItemClickListener (dette); urls = getResources (). getStringArray (R.array.URLs); progressBar = (ProgressBar) findViewById (R.id.progressbar); progressLayout = (LinearLayout) findViewById (R.id.progresslayout); } nedlasting av offentlig tomrom (visning) {} @Override public void onItemClick (AdapterView adapterView, View view, int i, long l) {editText.setText (urls [i]); }}Til nå kan programmet kompileres uten problemer, i denne klassen deklarerer vi variablene:
- editText
- listevisning
- nettadresser
- progressBar
- progressLayout
Et tekstfelt, en liste, et strengarrangement, en fremdriftslinje og en lineær layout.
I onCreate -metoden Vi tilordner dem den respektive visningen som tilhører dem og som ble opprettet i XML -filen til aktiviteten, med unntak av nettadressene som tilordner dens verdier fra verdimappen i strengfilen og hvis arrangement er erklært som følger:
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.webpDen tomme metoden for nedlasting (visning) vil bli fylt med koden som skal laste ned og som er koblet til Last ned -knappen Bot gjennom onclick -attributtet. Til slutt onitemclick -metoden som tilhører listevisning, fyller det ut tekstfeltet når du klikker på en av nettadressene i listen. Når denne koden er samlet, vil den se slik ut:
I det neste trinnet vil vi lage metodene som vil fortsette til nedlastingen, ved å følge disse trinnene:
- Lag et objekt i URL -klassen (java.net) som representerer nettadressen du skal laste ned.
- Åpne tilkoblingen med det objektet.
- Les dataene (via web) ved hjelp av input stream -klassen i en byte -matrise.
- Åpne / opprett en utdatastrømfil der nettadressene blir lagret på SD -kortet.
- Skriv dataene til den filen.
- Og til slutt stenge forbindelsen.
Foreløpig vil det se slik ut:
offentlig boolsk nedlasting usingThreads (strengkobling) {boolsk bekreftelse = false; URL downloadLink = null; HttpURLConnection conne = null; InputStream inputStream = null; prøv {downloadLink = ny URL (lenke); tilkobling = (HttpURLConnection) downloadLink.openConnection (); inputStream = conne.getInputStream (); } catch (MalformedURLException e) {e.printStackTrace (); } fangst (IOException e) {e.printStackTrace (); } endelig {if (connex! = null) {connex.disconnect (); } if (inputStream! = null) {prøve {inputStream.close (); } fangst (IOException e) {e.printStackTrace (); }}} returbekreftelse; }Denne metoden vi har bygget trenger bare en String som vil være nettadressen du skal laste ned, er boolsk For å bekrefte nedlastingen, er downloadLink URL -objektet, tilkoblingen er forbindelsen som vil bli gjort for å få tilgang til objektet, og inputStream er den som vil lese dataene hvis vi prøver å bruke denne metoden på knappen nedlastingBot programmet ville stoppe fordi det ikke var i stand til å kjøre på hovedtråden.
Her går vi med bruk av tråder, det er to måter å gjøre dette med en klasse, og det er ved å utvide denne klassen til tråd eller implementere Runnable -klassen, denne klassen er ikke en tråd, den lar deg bare lage en metode som du kan kjøre på et øyeblikk, og hvis du oppretter en egen tråd, kan du kjøre den i den.
Inne i nedlastingsknappen skriver vi denne koden, og den vil se slik ut:
nedlasting av offentlig tomrom (visning) {Thread mThread = new Thread (new mRunn ()); mThread.start (); }Her lager vi en ny tråd som trenger et Runnable -objekt som vi lager i en privat klasse som dette:
privat klasse mRunn implementerer Runnable {@Override public void run () {download usingThreads (urls [0]); }}Lag en privat klasse
MerkHusk at dette er alt i Java -klassen for vår eneste aktivitet.
Med streken:
last ned med UsingThreads (urls [0]);Vi kaller funksjonen som vi opprettet der vi åpnet tilkoblingen, et element i URL -matrisen sendes til den slik at den kan lese dataene fra den adressen. Senere vil det bli endret.
Hvis vi prøvde å kjøre denne applikasjonen ved å trykke på knappen, ville applikasjonen stoppe, fordi vi trenger en spesiell tillatelse for å få tilgang til internett, som er forespurt gjennom manifestet for applikasjonen vår. Legger til linjen før etiketten:
For å bekrefte at programmet faktisk utfører nedlastningen, legger vi til noen få kodelinjer i nedlastingsmetode ved hjelp av Threads, det vil se slik ut:
offentlig boolsk nedlasting usingThreads (strengkobling) {boolsk bekreftelse = false; URL downloadLink = null; HttpURLConnection conne = null; InputStream inputStream = null; FileOutputStream archOutputStream = null; Filfil = null; prøv {downloadLink = ny URL (lenke); tilkobling = (HttpURLConnection) downloadLink.openConnection (); inputStream = conne.getInputStream (); file = new File (Environment.getExternalStoragePublicDirectory (Environment.DIRECTORY_DOWNLOADS) + "/" + Uri.parse (link) .getLastPathSegment ()); archOutputStream = ny FileOutputStream (fil); int Les = -1; byte [] buffer = ny byte [1024]; mens ((Read = inputStream.read (buffer))! = -1) {archOutputStream.write (buffer, 0, Read); } bekreftelse = sant; } catch (MalformedURLException e) {e.printStackTrace (); } fangst (IOException e) {e.printStackTrace (); } endelig {if (connex! = null) {connex.disconnect (); } if (inputStream! = null) {prøve {inputStream.close (); } fangst (IOException e) {e.printStackTrace (); }} hvis (archOutputStream! = null) {prøve {archOutputStream.close (); } fangst (IOException e) {e.printStackTrace (); }}} returbekreftelse; } FileOutputStream archOutputStream = null; Filfil = null;Erklæringene til disse objektene representerer skriving av filen som leses, og den tomme filen der lesingen vil bli lagret.
file = new File (Environment.getExternalStoragePublicDirectory (Environment.DIRECTORY_DOWNLOADS) + "/" + Uri.parse (urls [0]). getLastPathSegment ()); archOutputStream = ny FileOutputStream (fil); int Les = -1; byte [] buffer = ny byte [1024]; mens ((Read = inputStream.read (buffer))! = -1) {archOutputStream.write (buffer, 0, Read); } bekreftelse = sant;"Fil" er det tomme filobjektet hvis adresse er konstruert ved å få tilgang til SD -kortet "Environment.getExternalStoragePublicDirectory (Environment.DIRECTORY_DOWNLOADS)" og legge til en skråstrek "/" og det siste segmentet av URL -en som generelt representerer navnet på filen til nedlasting, oppnår vi dette med getLastPathSegment () -metoden.
Før vi tester programmet, vil vi legge til en siste tillatelse i manifestet:
Etter å ha kjørt programmet på emulatoren eller Android -enheten, når vi trykker på knappen, ser vi at det tilsynelatende ikke skjer noe, men hvis vi sjekker nedlastingsmappen med en filutforsker, vil vi innse at det første elementet på listen er lastet ned; et bilde som heter 1.jpg.webp.
Å gjøre det dynamisk applikasjon og implementer URL -ene til listevisningen, vil vi oppdatere nedlastingsmetode (visning) og vi vil legge til dette, som den første linjen:
Stringlink = editText.getText (). ToString ();Og i mRunn klasse vi legger til dette før kjøre () metoden:
privat klasse mRunn implementerer Runnable {private String link; offentlig mRunn (strengkobling) {this.link = lenke; } @Override public void run () {download usingThreads (link); }}Og i mRunn klasse vi legger til dette før kjøre () metoden:
Så vi kan sende koblingsvariabelen fra tekstfeltet til metoden som utfører nedlastingen. Applikasjonen på dette tidspunktet er fullt funksjonell, selv om den mangler litt brukervennlighet, så vi vil prøve å fikse dette ved å bruke fremdriftslinjen som vi erklærte i begynnelsen.
I mRunn -klassen i kjøre () metoden vil vi inkludere:
MainActivity.this.runOnUiThread (new Runnable () {@Override public void run () {progressLayout.setVisibility (View.VISIBLE);}});Før samtalen til nedlastingusandoThreads. Dette vil få lastelinjen til å vises når vi trykker på knappen, i den siste klausulen i nedlastingsmetode ved hjelp av Threads.
Vi vil legge til:
this.runOnUiThread (new Runnable () {@Override public void run () {progressLayout.setVisibility (View.GONE);}});Så når nedlastingen er fullført, forsvinner linjen igjen. Dette vil skje uansett om nedlastingen er vellykket eller ikke.
Og dette har vært alt, ett kort implementering av flere tråderDette er litt kjedelig og gir noen komplikasjoner for mer komplekse applikasjoner.Den mest effektive måten å utføre denne oppgaven på, ved å laste ned noen bilder i vårt tilfelle, er å bruke AsyncTasks.