Image
15.5.2016 2 Comments

Seriál: Programujeme pre Android 20 / AsyncTask, Handler, HandlerThread

V tejto časti seriálu si v krátkosti popíšeme význam tried súvisiacich s vykonávaním úloh (tasks) v samostatných vláknach (threads). Vykonávanie časovo náročných úloh mimo hlavného používateľského vlákna (main UI thread) aplikácie je príznačnou črtou Androidu. OS týmto spôsobom rieši problém blokovania (not responding) spustených aktivít, ktorých dôvodom je zväčša vykonávanie kódu náročného na systémové prostriedky – I/O operácie, práca v sieťovom prostredí, nadväzovanie komunikácie...

Responzibilný výkon programového kódu je teda zabezpečovaný pomocou tried využívajúcich samostatné vlákna, z ktorých je najznámejšou trieda AsyncTask. Tá má však niekoľko obmedzení a preto si uvedieme ďalšie možnosti a postupne sa budeme venovať všetkým súvisiacim triedam.

AsyncTask

Táto trieda umožňuje spustenie kódu na pozadí (background) a zápis výsledku do UI vlákna bez potreby detailnej správy vlákien resp. riadiacich (obslužných) programov (handlers). Ide o tzv. pomocnú triedu (helper class), ktorú možno v princípe použiť na jednorázové spustenie špecifickej úlohy na pozadí. Pre aplikačné použitie metód triedy AsyncTask je nutné vytvoriť potomka tejto triedy a povinne definovať (override) metódu doInBackground(). Štvoricu používaných metód triedy AsyncTask ďalej dopĺňajú metódy onPreExecute(), onProgressUpdate() a onPostExecute(). Asynchrónne vykonanie úloh na pozadí, resp. v samostatnom vlákne, je riadené pomocou nasledujúcich synchronizovaných callback metód:

onPreExecute()

vykonaná v UI vlákne pred spustením úlohy na pozadí

doInBackground()

vykonanie úlohy v samostatnom vlákne – po ukončení onPreExecute()

onProgressUpdate()

vykonaná v UI vlákne pomocou publishProgress() – odoslanie informácie o priebehu vykonávania úlohy na pozadí

onPostExecute()

vykonaná v UI vlákne po skončení vykonania úlohy na pozadí – po ukončení doInBackground()

onCanceled()

vykonaná namiesto onPostExecute() spustením metódy cancel(boolean)

Jedným z najdôležitejších faktov súvisiacich s ďalšími triedami, ktoré si budeme popisovať, je ten, že úloha vykonaná na pozadí pomocou triedy AsyncTask, môže byť spustená (execute) iba jeden krát. Na spustenie novej (ďalšej) úlohy musíme vytvoriť novú inštanciu triedy AsyncTask.

Handler

Trieda Handler je určená na riadenie (obsluhu) správ nachádzajúcich sa v zozname úloh (MessageQueue) konkrétneho vlákna (thread). Každá inštancia triedy Handler je spriahnutá s konkrétnym vláknom a jeho zoznamom úloh.

Handlery sú používané na plnenie dvoch úloh:

1. prípravu správ (messages) a tzv. spustiteľných aplikačných blokov (runnables), ktoré majú byť vykonané v danom čase: post(Runnable), postAtTime, postDelayed, sendEmptyMessage, sendMessage, sendMessageAtTime, sendMessageDelayed,
2. prípravu úloh určených na vykonanie iným vláknom.

Handler je použiteľný rovnako pre UI vlákno ako aj pre novo vytvorené vlákna. V prípade UI vlákna je zoznamom úloh, ktoré budú handlerom riadené (obsluhované), zoznam úloh UI vlákna. Handlery sa okrem iného používajú aj na komunikáciu medzi samostatnými vláknami a UI vláknom aplikácie.

V prípade vytvorenia handlera pre UI vlákno je handler implicitne spriahnutý s týmto vláknom, jeho zoznamom úloh a jeho tzv. Looperom. Ak žiadame vytvoriť handler pre iné vlákno, musíme ho explicitne naviazať na Looper daného vlákna.

Vlákno predstavuje samostatne vykonávanú jednotku programového kódu s vlastným zásobníkom volaných metód, ich argumentami a lokálnymi premennými. Každá aplikácia je spustená minimálne v jednom vlákne. Spracovanie vlákien a procesov je samostatnou kapitolou, ktorej sa budeme venovať v budúcej časti seriálu. V tejto chvíli je pre nás dôležité poznať súvislosť medzi vláknom, jeho zoznamom úloh, looperom a handlerom, ktorú si ozrejmíme pomocou opisu triedy HandlerThread.

HandlerThread

Táto trieda pracuje s vláknom, jeho MessageQueue a Looperom:

Thread

unikátne vlákno obsahujúce Looper a MessageQueue, platí to aj pre hlavné UI vlákno

MessageQueue

zoznam úloh (tasks) = správy (messages) alebo spustiteľné bloky (runnables)

Looper

správca zoznamu úloh daného vlákna – spracováva úlohy zoradené v zozname úloh a zasiela správy riadiacemu, resp. obslužnému programu

Používanie konceptu HandlerThread má oproti AsyncTask a Thread+Looper tri zásadné výhody:

1. HandlerThread automaticky spravuje zabudovaný built-in Looper,
2. Looper podobne ako AsyncTask zabezpečuje spracovanie úloh (dispatchMessage, runnable.run()) na pozadí v sekvenčnom poradí čo znamená, že nedochádza k nepredvídaným zmenám údajovej vrstvy,
3. Looper udržiava vlákno vo funkčnom stave až pokiaľ nie je zrušené pomocou metódy quit() čo znamená, že na spustenie novej (ďalšej) úlohy nie je nutné vytvárať novú inštanciu triedy HandlerThread.

Obr. 1 Thread, MessageQueue, Looper

Zjednodušený programový kód implementujúci HandlerThread má nasledujúcu štruktúru:

1. vytvorenie inštancie triedy Handler pre UI vlákno a inštancie vlastnej triedy MyThread rozširujúcej HandlerThread:

public class MyActivity extends Activity {

 private Handler mUIHandler = new Handler();

 private MyThread mThread;

 

 @Override

 protected void onCreate(Bundle savedInstanceState) {

  ...

  mThread = new MyThread("HandlerThread");

2. definícia metódy Runnable.run() úlohy:

  Runnable task = new Runnable() {

   @Override

   public void run() {

    ...

   }

  });

3. štart nového vlákna (spustenie jeho run() metódy):

  mThread.start();

4. spriahnutie Handlera s Looperom triedy MyThread:

  mThread.prepareHandler();

5. vykonanie úlohy:

  mThread.postTask(task);

 }

6. zastavenie nového vlákna:

 @Override

 protected void onDestroy() {

  mThread.quit();

  ...

 }

}

7. implementácia triedy MyThread:

public class MyThread extends HandlerThread {

 private Handler mHandler;

 

 public MyThread(String name) { super(name); }

 public void postTask(Runnable task) { mHandler.post(task); }

 public void prepareHandler() { mHandler = new Handler(getLooper()); }

}

Zobrazit Galériu
Autor: Marek Sopko

Nechajte si posielať prehľad najdôležitejších správ emailom

Mohlo by Vás zaujímať

ITPro

Linux súkromne i pracovne v2.0 (14. časť): Small Business Server

09.11.2016 14:57

Pojem Small Business Server (malý firemný server) začala používať spoločnosť Microsoft ešte v roku 2000 na označenie servera, ktorý ­dokázal plniť úlohy niekoľkých samostatných serverov. Aplikačná vrs ...

ITPro

Industry 4.0: Fikcia alebo už realita?

09.11.2016 14:52

Štvrtá priemyselná revolúcia je pomenovanie rozsiahlych zmien prudko vstupujúcich do súčasného priemyslu. Nositeľom týchto zmien je digitalizácia výroby a optimalizácia všetkých podnikových procesov v ...

ITPro

Vývoj aplikácií UWP pre Xbox One II.

09.11.2016 14:47

V predošlej časti sme ukázali postup, ako si ­vytvoriť vývojársky účet a aktivovať vývojársky režim na hernej konzole Xbox One, aby ste mohli testovať svoje aplikácie. Výhodou hernej konzoly Xbox je v ...

2 Comments

  1. Pozor na zmenu orientacie zariadenia reakcia na: Seriál: Programujeme pre Android 20 / AsyncTask, Handler, HandlerThread
    15.5.2016 19:05
    Odporucam doplnit info o tom ze v pripade updatovania UI cez AsyncTask treba pouzivat WeakReference na activity pretoze pri otoceni zariadenia sa aktivita znici no asynctask pokracuje na pozadi a snazi sa updatovat neexistujuce UI. Da sa to osetrit no su s tym opletacky. Tiez odporucam pozriet AsyncTaskLoader
    Reagovať
    • RE: Pozor na zmenu orientacie zariadenia reakcia na: Pozor na zmenu orientacie zariadenia
      15.5.2016 19:05
      Este aby som nezabudol tak dobry napad je pouzit Fragmenty a nastavim im setRetainInstance na true :)
      Reagovať

Vyhľadávanie

Kyocera - prve-zariadenia-formatu-a4-s-vykonom-a3

Najnovšie videá