Program Android: Procesy, vlákna a služby

V tomto tutoriálu vysvětlíme jak Android funguje při spuštění služby, popíšeme, z čeho se prováděcí vlákna skládají a o čem jsou procesy. To nám umožní pochopit způsob spouštění našich aplikací, což nám poskytne větší kontrolu a stabilitu na mobilních zařízeních, kde budou nainstalovány.

Vlákno


Když uživatel spustí aplikaci, Android vytvoří vlákno s názvem main (main). Toto vlákno je velmi důležité, protože má na starosti správu událostí, které uživatel spouští u příslušných komponent, a také zahrnuje události, které vykreslují obrazovku. Vlákno spuštění, nejmenší část, kterou může zpracovat plánovač v operačním systému, v tomto případě Android (s linuxovým jádrem).

The implementace více vláken které jsou zpracovávány současně ve stejné aplikaci (nazývejte to souběžnost, která odkazuje na simultánní provádění), je známé jako vícevláknové. Je použito vícevláknové zpracování, aby tato vlákna sdílela prostředky A to je to, co proces zahrnuje, pamatujte, že to lze aplikovat programově v kódu stejné aplikace, implementace multithreadingu na úrovni operačního systému na nás nezávisí.

Začátek životního cyklu aplikace zahrnuje generování nového procesu Linux, kterému je přiřazeno hlavní vlákno nebo vlákno UI (vlákno, které je zodpovědné za grafické zpracování aplikace, vlákno uživatelského rozhraní v angličtině).

PoznámkaŽivotní cyklus zahrnuje provedení metod: onCreate (), onStart () a onResume (); na jeho začátku a na jeho konci: onPause (), onStop () a onDestroy ().

Proces může být vynucen zavřením systému Android kvůli nedostatku paměti, tento typ případu je vzácný kvůli technologickému pokroku, ale stále se to stává.

Otázkou je: Které procesy se Android rozhodne zavřít?

Ty jsou uzavřeny porovnáním jejich úrovně důležitosti a je shrnuto následovně:

Nejdůležitější: procesy v popředíUživatel s uvedeným procesem interaguje (metoda onResume () uvedeného procesu právě běží). Existuje služba, která provozuje své metody životního cyklu. Nebo existuje a BroadcastReceiver běh jeho metoda onReceive ().

Druhý nejdůležitější: Viditelné procesyAktivita s voláním na metoda onPause (). Služba spojená s viditelnou aktivitou (vázaná služba).

Třetí nejdůležitější: Proces se službouUživatel neinteraguje přímo s procesem. Proces má službu spuštěnou na pozadí.

Druhý nejméně důležitý: Proces na pozadíNeexistuje žádný typ interakce s uživatelem. Proces, který uživatel naposledy viděl, bude poslední, který bude zničen.

Nejméně důležité: Prázdný procesNemá žádné aktivní součásti. Proces je stále aktivní pro účely ukládání do mezipaměti, což brání uživateli vrátit se k použití tohoto procesu.

Ten druhý, prázdný proces, je první, který bude ukončen v případě nedostatku paměti. Aplikace, která implementuje službu, kde je vytvořeno vlákno pro stahování obsahu z internetu, bude důležitější než aplikace, která vytvoří vlákno bez implementace služby, takže je pravděpodobnější, že bude ukončena před dokončením stahování. , protože jsou to dlouhodobé procesy.

Pochopit multhreading podívejme se, jak Android zvládá své hlavní vlákno.

PROCESS A má uživatelské rozhraní nebo HLAVNÍ vlákno, toto vlákno zpracovává a fronta zpráv nebo fronta zpráv, která běží, když se vlákno stane nečinným, kdo to řeší? The Looper.

Looper je třída uživatelského rozhraní Android Java že spolu s Třída psovoda, zpracovává události uživatelského rozhraní, jako jsou stisknutí tlačítka, překreslení obrazovek a přepínače orientace. Události lze také použít k načtení obsahu do služby HTTP, změně velikosti obrázků a spouštění vzdálených požadavků. Klíčovou vlastností těchto tříd je, že jsou schopny implementovat vzor souběžnosti.

The Třída Android Looper obsahuje a MessageQueue (fronta zpráv) a je spojena pouze s tématem, ze kterého byla vytvořena. Upozorňujeme, že toto připojení nelze přerušit a že lOoper nelze jej připojit k žádnému jinému vláknu. Looper je také na místním úložišti a lze jej volat pouze ze statické metody. Pracovní metoda zkontroluje, zda je Looper již přidružen k vláknu, a poté statická metoda vytvoří Looper. Poté lze smyčku použít ke kontrole zpráv ve frontě.

Zatím rozumíme několika konceptům: proces, vlákno, vlákno uživatelského rozhraní, smyčka, ale stále nevíme, proč vícevláknové.

Dlouhodobé operace


Je považováno za dlouhé trvání jakékoli metody, jejíž provedení přesáhne 5 sekund, což spustí typickou zprávu „aplikace nereaguje. Chcete to zavřít?

Co mohou být tyto operace?: Přístup k internetu, Dotazy SQL, analýza XML / HTML / JSON, komplexní grafické zpracování. Jakákoli z těchto operací, které jsou spuštěny v hlavním vlákně, ji zablokuje, a protože je to ta, která zpracovává grafické uživatelské rozhraní, je interpretována jako zmrazení, které se Android rozhodne zavřít.

Představme si, že některá z těchto operací trvá 7 sekund a uživatel se rozhodne něco napsat v nějakém zadávání textu, takže zatímco těchto 7 sekund ještě neuplynulo, vlákno uživatelského rozhraní nemůže aktualizovat zobrazení, aby uživatel ocenil, že píše, a generuje tedy zmrazení, spustí se zpráva „žádná odpověď“, ve které máte dvě možnosti, počkat nebo zničit, ačkoli nikdy nemůžete vědět, jak dlouho čekat, v závislosti na frontě zpráv to může být několik sekund nebo dokonce minut které mají hlavní vlákno.

Jak zamezíme zmrazení?


Pomocí vláken nebo služeb, v závislosti na tom, zda úkol vyžaduje úpravu zobrazení, je v tomto případě služba implementována, protože pohled na aplikaci nelze upravit mimo vlákno uživatelského rozhraní. Nejlepší způsob, jak zabránit zamrznutí, je použít asynchronní úkoly s třídou AsyncTask, v tomto kurzu implementujeme více vláken, abychom porozuměli chování architektury Android.

Kód a vývoj


Projekt, který vytvoříme příště bude založeno na stažení obrázku pomocí kterého musíme vytvořit vlákno, které nám umožní spravovat přístup a stahování přes internet, protože HLAVNÍ nebo UI Thread nepovoluje tuto akci.

Začneme vytvořením nového projektu s prázdnou aktivitou, tento projekt jsme pojmenovali "MultiThreadExample", s jedinou jednoduchou činností vytvoříme strukturu souboru XML které k této činnosti patří.

 
Máme textové pole, tlačítko, lineární rozložení, které odpovídá neurčité načítací liště, kterou použijeme později, a zobrazení seznamu, které obsahuje řadu adres URL obrázků hostovaných na internetu. V souboru, který obsahuje třídu Java pro naši (jedinečnou) aktivitu, je zapsán s následujícím kódem:
 balíček com.omglabs.multithreaexample; importovat android.support.v7.app.AppCompatActivity; import android.os.Bundle; import android.view.View; import android.widget.AdapterView; import android.widget.EditText; importovat android.widget.LinearLayout; import android.widget.ListView; import android.widget.ProgressBar; veřejná třída MainActivity rozšiřuje AppCompatActivity implementuje AdapterView.OnItemClickListener {private EditText editText; soukromý ListView listView; soukromé adresy URL String []; soukromá ProgressBar progressBar; soukromé 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 (this); urls = getResources (). getStringArray (R.array.URLs); progressBar = (ProgressBar) findViewById (R.id.progressbar); progressLayout = (LinearLayout) findViewById (R.id.progresslayout); } public void download (View view) {} @Override public void onItemClick (AdapterView adapterView, View view, int i, long l) {editText.setText (urls [i]); }} 
Až dosud lze aplikaci bez problémů kompilovat, v této třídě deklarujeme proměnné:
  • editText
  • zobrazení seznamu
  • URL
  • ukazatel průběhu
  • rozvržení postupu

Textové pole, seznam, uspořádání řetězců, ukazatel průběhu a lineární rozvržení.

V metoda onCreate Přiřadíme jim příslušný pohled, který jim patří a které byly vytvořeny v souboru XML aktivity, s výjimkou adres URL, které přiřazují své hodnoty ze složky hodnot v řetězcovém souboru a jejichž uspořádání je deklarováno jak následuje:

 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 
Stažení prázdné metody (zobrazení Zobrazit) bude vyplněno kódem, který provede stahování a který je propojen s Tlačítko Stáhnout Bot prostřednictvím atributu onclick. Nakonec metoda onitemclick které patří zobrazení seznamu, vyplní textové pole, když kliknete na některou z adres URL obsažených v seznamu. Po kompilaci bude tento kód vypadat takto:

V dalším kroku vytvoříme metody, které budou pokračovat ve stahování, podle těchto kroků:

  • Vytvořte objekt třídy URL (java.net), který bude představovat URL ke stažení.
  • Otevřete připojení pomocí tohoto objektu.
  • Čtěte data (přes web) pomocí třídy vstupního proudu v bajtovém poli.
  • Otevřete / vytvořte soubor výstupního proudu, kde budou data o URL uložena na SD kartu.
  • Zapište data do tohoto souboru.
  • A nakonec ukončete spojení.

Zatím to bude vypadat takto:

 public boolean download usingThreads (String link) {boolean confirmation = false; URL downloadLink = null; HttpURLConnection Conne = null; InputStream inputStream = null; zkusit {downloadLink = nová URL (odkaz); připojení = (HttpURLConnection) downloadLink.openConnection (); inputStream = connect.getInputStream (); } catch (MalformedURLException e) {e.printStackTrace (); } catch (IOException e) {e.printStackTrace (); } konečně {if (Connex! = null) {connectx.disconnect (); } if (inputStream! = null) {try {inputStream.close (); } catch (IOException e) {e.printStackTrace (); }}} potvrzení vrácení; } 
Tato metoda, kterou jsme vytvořili, bude potřebovat pouze a Tětiva což bude URL ke stažení, je booleovský Chcete -li potvrdit stahování, downloadLink je objekt URL, připojení je připojení, které bude vytvořeno pro přístup k objektu, a inputStream je to, které bude pokračovat ve čtení dat, pokud se pokusíme použít tuto metodu na tlačítku downloadBot aplikace by se zastavila, protože by nemohla běžet na hlavní vlákno.

Tady jdeme s použitím vláken, existují dva způsoby, jak to udělat s třídou, a to tím, že tuto třídu rozšíříte na Thread nebo implementujete třídu Runnable, tato třída není vlákno, které vám jednoduše umožňuje vytvořit metodu, kterou může běžet v určitém okamžiku a pokud vytvoříte samostatné vlákno, spusťte jej v něm.

Do tlačítka pro stažení napíšeme tento kód a bude vypadat takto:

 public void download (Zobrazit zobrazení) {Thread mThread = new Thread (new mRunn ()); mThread.start (); } 
Zde vytváříme nové vlákno, které potřebuje objekt Runnable, který vytvoříme v soukromé třídě takto:
 soukromá třída mRunn implementuje Runnable {@Override public void run () {download usingThreads (urls [0]); }} 
Vytvořit soukromou třídu

PoznámkaPamatujte, že to je vše ve třídě Java naší jediné aktivity.

S řádkem:

 stahovat pomocí Threads (URL [0]);
Voláme funkci, kterou jsme vytvořili tam, kde jsme otevřeli připojení, je jí předána položka pole URL, aby mohla číst data z této adresy. Později bude upraven.

Pokud bychom se pokusili spustit tuto aplikaci stisknutím tlačítka, aplikace by se zastavila, protože pro přístup k internetu potřebujeme speciální povolení, které je požadováno prostřednictvím manifestu naší aplikace. Přidání řádku před štítek:

 
Nyní, abychom ověřili, že aplikace skutečně provádí stahování, přidáme do řádku několik řádků kódu metoda stahování pomocí Threads, bude to vypadat takto:
 public boolean download usingThreads (String link) {boolean confirmation = false; URL downloadLink = null; HttpURLConnection Conne = null; InputStream inputStream = null; FileOutputStream archOutputStream = null; Soubor souboru = null; zkusit {downloadLink = nová URL (odkaz); připojení = (HttpURLConnection) downloadLink.openConnection (); inputStream = connect.getInputStream (); soubor = nový soubor (Environment.getExternalStoragePublicDirectory (Environment.DIRECTORY_DOWNLOADS) + "/" + Uri.parse (odkaz) .getLastPathSegment ()); archOutputStream = nový FileOutputStream (soubor); int Read = -1; byte [] buffer = nový byte [1024]; while ((Read = inputStream.read (buffer))! = -1) {archOutputStream.write (buffer, 0, Read); } potvrzení = true; } catch (MalformedURLException e) {e.printStackTrace (); } catch (IOException e) {e.printStackTrace (); } konečně {if (Connex! = null) {connectx.disconnect (); } if (inputStream! = null) {try {inputStream.close (); } catch (IOException e) {e.printStackTrace (); }} if (archOutputStream! = null) {try {archOutputStream.close (); } catch (IOException e) {e.printStackTrace (); }}} potvrzení vrácení; } FileOutputStream archOutputStream = null; Soubor souboru = null; 
Deklarace těchto objektů představují zápis souboru, který se čte, a prázdný soubor, kam bude čtení uloženo.
 soubor = nový soubor (Environment.getExternalStoragePublicDirectory (Environment.DIRECTORY_DOWNLOADS) + "/" + Uri.parse (adresy URL [0]). getLastPathSegment ()); archOutputStream = nový FileOutputStream (soubor); int Read = -1; byte [] buffer = nový byte [1024]; while ((Read = inputStream.read (buffer))! = -1) {archOutputStream.write (buffer, 0, Read); } potvrzení = true; 
"Soubor" je prázdný objekt souboru, jehož adresa je vytvořena přístupem na kartu SD "Environment.getExternalStoragePublicDirectory (Environment.DIRECTORY_DOWNLOADS)" a přidáním lomítka "/" a posledního segmentu adresy URL, která obecně představuje název souboru stáhnout, dosáhneme toho metodou getLastPathSegment ().

Před testováním aplikace přidáme do manifestu poslední oprávnění:

 
Po spuštění aplikace na emulátoru nebo zařízení Android po stisknutí tlačítka uvidíme, že se zjevně nic neděje, ale pokud v Průzkumníku souborů zkontrolujeme složku Stahování, zjistíme, že byla stažena první položka v seznamu; fotografie s názvem 1.jpg.webp.

Udělat to dynamická aplikace a implementujte adresy URL seznamu, budeme aktualizovat metoda stahování (Zobrazit zobrazení) a přidáme to jako první řádek:

 Řetězcový odkaz = editText.getText (). ToString ();
A v mRunn třída přidáme to před metodou run ():
 soukromá třída mRunn implementuje Runnable {private String link; public mRunn (String link) {this.link = link; } @Override public void run () {stáhnout usingThreads (odkaz); }}
A v mRunn třída přidáme to před metodou run ():

Můžeme tedy předat proměnnou odkazu z textového pole metodě, která provádí stahování. V tuto chvíli je aplikace plně funkční, i když postrádá trochu uživatelské přívětivosti, takže se to pokusíme napravit pomocí indikátoru průběhu, který jsme deklarovali na začátku.

Do třídy mRunn v metodě run () zahrneme:

 MainActivity.this.runOnUiThread (new Runnable () {@Override public void run () {progressLayout.setVisibility (View.VISIBLE);}}); 
Před voláním na downloadusandoThreads. Tím se lišta načítání zobrazí, když stiskneme tlačítko v klauzuli konečne metoda stahování pomocí Threads.

Přidáme:

 this.runOnUiThread (new Runnable () {@Override public void run () {progressLayout.setVisibility (View.GONE);}}); 
Po dokončení stahování tedy lišta opět zmizí. K tomu dojde bez ohledu na to, zda je stahování úspěšné.
A to bylo všechno, jedna krátká implementace více vlákenTo je trochu zdlouhavé a přináší to komplikace pro složitější aplikace.Nejúčinnějším způsobem, jak toho dosáhnout, v našem případě stažení některých obrázků, je použití AsyncTasks.

wave wave wave wave wave