I denne vejledning forklarer vi hvordan Android fungerer, når man kører en tjeneste, vil vi beskrive, hvad eksekveringstrådene består af, og hvad processerne handler om. Dette giver os mulighed for at forstå den måde, vores applikationer køres på, hvilket giver os større kontrol og stabilitet på de mobile enheder, hvor de vil blive installeret.
Tråd
Når brugeren kører et program, Android opretter en tråd kaldet main (main). Denne tråd er meget vigtig, fordi den har ansvaret for at styre de begivenheder, som brugeren udløser til de relevante komponenter og også inkluderer de begivenheder, der tegner skærmen. En udførelsestråd, den mindste del, der kan behandles af en planlægger i et operativsystem, i dette tilfælde Android (med Linux -kerne).
Det implementering af flere tråde der behandles på samme tid i den samme applikation, (kald det samtidighed, som refererer til samtidig udførelse), det er kendt som multithreading. Multithreading anvendes, så disse tråde deler ressourcer Og det er det, en proces består af, husk, at dette kan anvendes programmatisk inden for koden for den samme applikation, implementeringen af multithreading på operativsystemniveau afhænger ikke af os.
Begyndelsen på en applikations livscyklus inkluderer generering af en ny Linux -proces, der er tildelt en hovedtråd eller UI -tråd (tråden, der er ansvarlig for den grafiske behandling af applikationen, brugergrænsefladetråd på engelsk).
BemærkLivscyklussen omfatter udførelse af metoderne: onCreate (), onStart () og onResume (); ved starten og ved slutningen: onPause (), onStop () og onDestroy ().
En proces kan tvinges til at lukke af Android på grund af mangel på hukommelse, denne type sag er sjælden på grund af teknologiske fremskridt, men det sker stadig.
Spørgsmålet er: Hvilke processer beslutter Android at lukke?
Disse lukkes ved at sammenligne deres vigtighedsniveau, det opsummeres som følger:
Det vigtigste: forgrundsprocesserBrugeren interagerer med processen (metoden onResume () i processen kører i øjeblikket). Der er en service, der kører sine livscyklusmetoder. Eller er der en Broadcastmodtager kører hans onReceive () metode.
Den næstvigtigste: Synlige processerAktivitet med opkald til onPause () metode. Service knyttet til en synlig aktivitet (bunden service).
Den tredje vigtigste: Proces med en serviceBrugeren interagerer ikke direkte med processen. Processen har en tjeneste, der kører i baggrunden.
Den anden mindst vigtige: BaggrundsprocesDer er ingen form for interaktion med brugeren. Den proces, der senest blev set af brugeren, vil være den sidste, der ødelægges.
Det mindst vigtige: Tom procesDet har ingen aktive komponenter. Processen er stadig i live til cachelagring, hvilket forhindrer brugeren i at vende tilbage til brug af denne proces.
Sidstnævnte, den tomme proces, er den første, der afsluttes i tilfælde af mangel på hukommelse. Således vil en applikation, der implementerer en tjeneste, hvor der oprettes en tråd for at downloade indhold fra internettet, være vigtigere end en applikation, der opretter tråden uden at implementere en service, så det er mere sandsynligt, at det bliver afsluttet, før downloadet er fuldført. , fordi de er langvarige processer.
For at forstå multhreading lad os se, hvordan Android håndterer sin hovedtråd.
PROCESS A har et brugergrænseflade eller Hovedtråd, denne tråd håndterer en beskedkø eller beskedkø, som kører, når tråden bliver inaktiv, hvem håndterer dette? Det Looper.
Looper er en brugergrænseflade klasse af Android Java det sammen med Handler klasse, behandler brugergrænsefladehændelser som f.eks. tryk på knapper, tegninger, der tegnes om og orienteringsafbrydere. Begivenheder kan også bruges til at indlæse indhold i en HTTP -tjeneste, ændre størrelsen på billeder og udføre fjernanmodninger. Nøglefunktionen i disse klasser er, at de er i stand til at implementere et samtidighedsmønster.
Det Android Looper klasse indeholder en MessageQueue (meddelelseskø) og er kun forbundet med det emne, hvorfra det blev oprettet. Bemærk, at denne forbindelse ikke kan afbrydes, og at lLooper den kan ikke vedhæftes nogen anden tråd. Looper er også på lokalt lager og kan kun kaldes fra en statisk metode. En iscenesættelsesmetode kontrollerer, om en Looper allerede er knyttet til en tråd, og derefter opretter den statiske metode Looper. Bagefter kan en loop bruges til at kontrollere meddelelserne i køen.
Indtil videre forstår vi flere begreber: proces, tråd, UI -tråd, looper, men vi ved stadig ikke, hvorfor multithreading.
Langsigtet drift
Det betragtes som lang varighed for enhver metode, hvis udførelse overstiger 5 sekunder, hvilket udløser den typiske meddelelse "applikationen reagerer ikke. Vil du lukke den?
Hvad kan disse operationer være?: Internetadgang, SQL -forespørgsler, XML / HTML / JSON -analyse, kompleks grafisk behandling. Enhver af disse operationer, der køres i hovedtråden, blokerer det, og da det er den, der håndterer den grafiske brugergrænseflade, tolkes det som en frysning, som android beslutter at lukke.
Lad os bare forestille os, at enhver af disse operationer varer 7 sekunder, og brugeren beslutter at skrive noget i noget tekstinput, så selvom disse 7 sekunder ikke er gået, kan UI -tråden ikke opdatere visningen, så brugeren værdsætter, at han skriver, og så det genererer en frysning, meddelelsen "intet svar" udløses, som du har to muligheder med, vent eller ødelæg, selvom du aldrig kan vide, hvor lang tid du skal vente, kan det være et par sekunder eller endda minutter afhængigt af meddelelseskøen der har hovedtråden.
Hvordan undgår vi at fryse?
Brug af tråde eller tjenester afhængigt af om opgaven kræver ændring af visningen, i dette tilfælde implementeres en tjeneste, fordi visningen af et program ikke kan ændres uden for UI -tråden. Den bedste måde at undgå frysning er at bruge asynkrone opgaver med AsyncTask -klassen, i denne vejledning implementerer vi flere tråde for at forstå opførslen af Android -arkitekturen.
Kode og udvikling
Det projekt, som vi vil oprette næste gang vil være baseret på en billedoverførsel hvormed vi skal oprette en tråd, der giver os mulighed for at administrere adgang og download over internettet, fordi HOVED eller UI -tråd tillader ikke denne handling.
Vi starter med at oprette et nyt projekt med en tom aktivitet, vi har titlen dette projekt "MultiThreadExample", med en enkelt enkel aktivitet vi vil oprette strukturen af XML -filen der hører til denne aktivitet.
Vi har et tekstfelt, en knap, et lineært layout, der svarer til en ubestemt indlæsningslinje, som vi vil bruge senere, og en listevisning, der indeholder en række URL'er til billeder, der er hostet på internettet. I filen, der indeholder Java -klassen til vores (unikke) aktivitet, er den skrevet med følgende kode:
pakke com.omglabs.multithreaexample; importer android.support.v7.app.AppCompatActivity; import android.os.Bundle; import android.view.View; importer android.widget.AdapterView; importer android.widget.EditText; import android.widget.LinearLayout; importer android.widget.ListView; importer android.widget.ProgressBar; public class MainActivity udvider AppCompatActivity implementerer AdapterView.OnItemClickListener {private EditText editText; private ListView listView; private String [] urls; private ProgressBar progressBar; private LinearLayout progressLayout; @Override beskyttet tomrum onCreate (Bundle gemtInstanceState) {super.onCreate (gemtInstanceState); 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); } download af offentligt tomrum (visning) {} @Override public void onItemClick (AdapterView adapterView, View view, int i, long l) {editText.setText (urls [i]); }}Indtil nu kan applikationen kompileres uden problemer, i denne klasse erklærer vi variablerne:
- editText
- listView
- urls
- progressBar
- progressLayout
Et tekstfelt, en liste, et strengarrangement, en statuslinje og et lineært layout.
I onCreate -metode Vi tildeler dem den respektive visning, der tilhører dem, og som blev oprettet i XML -filen for aktiviteten, med undtagelse af de URL'er, der tildeler dens værdier fra værdimappen i strengfilen, og hvis arrangement er erklæret 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 metodeoverførsel (visning af visning) vil blive udfyldt med den kode, der skal overføre, og som er knyttet til Download -knap Bot via attributten onclick. Endelig onitemclick metode som tilhører listevisning, udfylder det tekstfeltet, når du klikker på en af webadresserne på listen. Når denne kode er udarbejdet, vil den se sådan ud:
I det næste trin opretter vi de metoder, der fortsætter til downloadingen, ved at følge disse trin:
- Opret et objekt af URL -klassen (java.net), der repræsenterer url'en til download.
- Åbn forbindelsen ved hjælp af dette objekt.
- Læs dataene (via web) ved hjælp af inputstream -klassen i et byte -array.
- Åbn / opret en output -streamfil, hvor url -dataene gemmes på SD -kortet.
- Skriv dataene til den fil.
- Og afslut endelig forbindelsen.
For nu vil det se sådan ud:
offentlig boolsk download ved hjælp afThreads (strenglink) {boolsk bekræftelse = falsk; URL downloadLink = null; HttpURLConnection conne = null; InputStream inputStream = null; prøv {downloadLink = ny URL (link); forbindelse = (HttpURLConnection) downloadLink.openConnection (); inputStream = conne.getInputStream (); } fangst (MalformedURLException e) {e.printStackTrace (); } fangst (IOException e) {e.printStackTrace (); } endelig {if (connex! = null) {connex.disconnect (); } hvis (inputStream! = null) {prøv {inputStream.close (); } fangst (IOException e) {e.printStackTrace (); }}} returbekræftelse; }Denne metode, som vi har bygget, behøver kun en Snor som vil være webadressen til download, er boolsk For at bekræfte overførslen er downloadLink URL -objektet, forbindelsen er forbindelsen, der vil blive oprettet for at få adgang til objektet, og inputStream er den, der vil læse dataene, hvis vi forsøger at bruge denne metode på knappen downloadBot applikationen ville stoppe på grund af ikke at kunne køre på hovedtråd.
Her går vi med brugen af tråde, der er to måder at gøre dette med en klasse, og det er ved at udvide denne klasse til Thread eller implementere Runnable -klassen, denne klasse er ikke en tråd, den giver dig simpelthen mulighed for at oprette en metode, som du kan køre i et øjebliksspecifikt, og hvis du opretter en separat tråd, kan du køre den i den.
Inde i download -knappen skriver vi denne kode, og den vil se sådan ud:
offentlig annulleret download (visning) {Thread mThread = ny tråd (ny mRunn ()); mThread.start (); }Her opretter vi en ny tråd, som har brug for et Runnable -objekt, som vi opretter i en privat klasse som denne:
privat klasse mRunn implementerer Runnable {@Override public void run () {download usingThreads (urls [0]); }}Opret privat klasse
BemærkHusk, at dette er alt i Java -klassen af vores eneste aktivitet.
Med stregen:
download usingThreads (urls [0]);Vi kalder den funktion, vi oprettede, hvor vi åbnede forbindelsen, et element i URL -arrayet sendes til det, så det kan læse dataene fra den adresse. Senere vil det blive ændret.
Hvis vi forsøgte at køre denne applikation ved at trykke på knappen, stoppede applikationen, fordi vi har brug for en særlig tilladelse til at få adgang til internettet, hvilket er anmodet om gennem manifestet af vores applikation. Tilføjelse af linjen før etiketten:
Nu for at kontrollere, at applikationen rent faktisk udfører overførslen, tilføjer vi et par linjer kode til download metode ved hjælp af Threads, det vil se sådan ud:
offentlig boolsk download usingThreads (strenglink) {boolsk bekræftelse = falsk; URL downloadLink = null; HttpURLConnection conne = null; InputStream inputStream = null; FileOutputStream archOutputStream = null; Filfil = null; prøv {downloadLink = ny URL (link); forbindelse = (HttpURLConnection) downloadLink.openConnection (); inputStream = conne.getInputStream (); file = ny fil (Environment.getExternalStoragePublicDirectory (Environment.DIRECTORY_DOWNLOADS) + "/" + Uri.parse (link) .getLastPathSegment ()); archOutputStream = ny FileOutputStream (fil); int Læs = -1; byte [] buffer = ny byte [1024]; mens ((Read = inputStream.read (buffer))! = -1) {archOutputStream.write (buffer, 0, Read); } bekræftelse = sand; } fangst (MalformedURLException e) {e.printStackTrace (); } fangst (IOException e) {e.printStackTrace (); } endelig {if (connex! = null) {connex.disconnect (); } hvis (inputStream! = null) {prøv {inputStream.close (); } fangst (IOException e) {e.printStackTrace (); }} hvis (archOutputStream! = null) {prøv {archOutputStream.close (); } fangst (IOException e) {e.printStackTrace (); }}} returbekræftelse; } FileOutputStream archOutputStream = null; Filfil = null;Deklarationerne for disse objekter repræsenterer skrivningen af den fil, der læses, og den tomme fil, hvor læsningen vil blive gemt.
file = ny fil (Environment.getExternalStoragePublicDirectory (Environment.DIRECTORY_DOWNLOADS) + "/" + Uri.parse (urls [0]). getLastPathSegment ()); archOutputStream = ny FileOutputStream (fil); int Læs = -1; byte [] buffer = ny byte [1024]; mens ((Read = inputStream.read (buffer))! = -1) {archOutputStream.write (buffer, 0, Read); } bekræftelse = sand;"Fil" er det tomme filobjekt, hvis adresse er konstrueret ved at få adgang til SD -kortet "Environment.getExternalStoragePublicDirectory (Environment.DIRECTORY_DOWNLOADS)" og tilføjelse af en skråstreg "/" og det sidste segment af URL'en, der generelt repræsenterer navnet på filen til download, opnår vi dette med getLastPathSegment () -metoden.
Inden vi tester applikationen tilføjer vi en sidste tilladelse til manifestet:
Efter at have kørt applikationen på emulatoren eller Android -enheden, når vi trykker på knappen, vil vi se, at der tilsyneladende ikke sker noget, men hvis vi tjekker Download -mappen med en filudforsker, vil vi indse, at det første element på listen er blevet downloadet; et foto kaldet 1.jpg.webp.
At gøre det dynamisk applikation og implementer URL'erne i listevisningen, vil vi opdatere downloadmetode (visning) og vi tilføjer dette som den første linje:
Stringlink = editText.getText (). ToString ();Og i mRunn klasse vi tilføjer dette før metoden run ():
privat klasse mRunn implementerer Runnable {private String link; offentlig mRunn (strenglink) {this.link = link; } @Override public void run () {download usingThreads (link); }}Og i mRunn klasse vi tilføjer dette, før metoden run ():
Så vi kan overføre linkvariablen fra tekstfeltet til den metode, der udfører overførslen. Applikationen på dette tidspunkt er fuldt funktionsdygtig, selvom den mangler en smule brugervenlighed, så vi vil forsøge at løse dette ved hjælp af den statuslinje, som vi erklærede i begyndelsen.
I mRunn -klassen i køre () metoden inkluderer vi:
MainActivity.this.runOnUiThread (new Runnable () {@Override public void run () {progressLayout.setVisibility (View.VISIBLE);}});Før opkaldet til downloadusandoThreads. Dette får ladestangen til at vises, når vi trykker på knappen i den sidste klausul i download metode ved hjælp af Threads.
Vi tilføjer:
this.runOnUiThread (new Runnable () {@Override public void run () {progressLayout.setVisibility (View.GONE);}});Så når overførslen er fuldført, forsvinder linjen igen. Dette sker, uanset om overførslen er vellykket eller ej.
Og dette har været alt, et kort implementering af flere trådeDette er lidt kedeligt og medfører nogle komplikationer til mere komplekse applikationer.Den mest effektive måde at udføre denne opgave på, ved i vores tilfælde at downloade nogle billeder, er at bruge AsyncTasks.