Platforma Android

Z Kiwiki
Skočit na navigaci Skočit na vyhledávání

Platforma Android a životný cyklus aplikácií bežiacich na tejto platforme je výrazne odlišný od životného cyklu aplikácií bežiacich na desktope. Desktopové aplikácie bežia ako relatívne samostatné procesy nezávisle od iných, paralelne bežiacich procesov.

Na rozdiel od desktopových aplikácií, Android aplikácie prechádzajú počas svojho behu (životného cyklu) rôznymi štádiami v závislosti na rôznych systémových udalostiach resp. prerušeniach (viď 1.1.1). Samotná Android aplikácia môže pozostávať zo štyroch základných súčastí medzi ktoré patria: Activity (aktivita), Content providers (poskytovatelia obsahu), Broadcast recievers (prijímatelia vysielania), Services (služby). Každá aplikácia môže byť tvorená ľubovolnou kombináciou týchto súčastí . V Aplikácii aAurela sa používa len komponenta Activity, ktorá bude ďalej bližšie opísaná.

Komponenta Activity

Komponenta Activity (ďalej len aktivita) tvorí základ používateľského rozhrania a predstavuje obdobu okna desktopovej aplikácie, prostredníctvom ktorého používateľ s aplikáciou interaguje. Jednu aplikáciu môže tvoriť niekoľko aktivít, kde každá má svoj význam a umožňuje používateľovi grafický vstup do rozdielnych častí aplikácie. Pre vývojárov reprezentuje každá aktivita samostatnú triedu.

Životný cyklus aktivity

Každá aktivita v rámci jednej a tej istej aplikácie má svoj vlastný životný cyklus. Životný cyklus je reprezentovaný rôznymi stavmi, ktorými aktivita počas svojho behu prechádza. Jednotlivé stavy životného cyklu Android aktivity sú nesmierne dôležité pre správne fungovanie aplikácie ako celku. Ich úlohou je zabrániť „pádu“ aplikácie pri práci s viacerými aktivitami, prípadne pri rôznych prerušeniach behu aktivity danej aplikácie.

Zmena stavu životného cyklu Android aktivity nastáva napr. pri zmene orientácie obrazovky zariadenia, minimalizovaní aplikácie stlačením domovského tlačidla, alebo pri prerušení aplikácie prichádzajúcim hovorom. Stavy, v ktorých sa Android aktivita môže nachádzať sú: Resumed, Paused, Stopped, Destroyed.

  • Resumed - stav kedy je aktivita v popredí, v interakcii s používateľom.
  • Paused - stav, v ktorom je aktivita pozastavená, mimo interakcie s používateľom (čiastočne viditeľná) napr. prekrytá dialógovým oknom.
  • Stoped - stav, v ktorom sa aktivita dostala na pozadie, stratila „pozornosť“ (úplne skrytá) napr. iná aktivita sa dostala do popredia.
  • Destroyed - stav, kedy je aktivita úplne ukončená, odstránená zo systémovej pamäte.

Created a Started nepovažujeme za samostatné stavy, označujú sa za stavy prechodné, čo znamená, že aktivita v nich nie je schopná zotrvať po určitý čas a takmer okamžite sa z nich posúva do stavu nasledujúceho.

  • Created - je moment, kedy systém vytvorí danú aktivitu.
  • Started - je moment, kedy sa aktivita stáva viditeľná.
Životný cyklus Android aktivity spolu s metódami spätného volania
Životný cyklus Android aktivity spolu s metódami spätného volania

Metódy spätného volania slúžia na zachytenie zmeny stavu a na vykonanie akcie ešte pred tým, než sa aktivita dostane do stavu iného. Metódy spätného volania je možné implementovať v triede samotnej aktivity. V závislosti na zmene stavu aktivity sú volané metódy: onCreate(), onStart(), onResume(), onPause(), onRestart(), onStop(), onDestroy(). Jediná povinná metóda spätného volania, ktorá musí byť v triede aktivity implementovaná je metóda onCreate(). Metóda onCreate() je volaná vždy pri prvotnom vytvorení aktivity a štandardne sa v nej nastavuje grafické rozhranie aktivity, inicializujú sa potrebné objekty a podobne. V tejto časti bol použitý zdroj .

Princípy a nástroje využité pri vývoji aplikácie

Táto časť pojednáva o základných princípoch systému Android a nástrojoch, ktoré boli pri vývoji aplikácie využité. Nástroje reprezentujú dve dôležité knižnice, na ktorých je postavené jadro aplikácie: - SQLite databáza a - asynchrónna práca s vláknami. Knižnice Room a RxJava sú vzájomne kompatibilné a v spolupráci výrazne uľahčujú vývoj robustnejších aplikácií na platforme Android.

SQLite databáza na platforme Android

SQLite je lokálna SQL databáza (uložená ako súbor v zariadení), ktorá disponuje všetkými funkciami relačných databáz. Platforma Android umožňuje pre ukladanie väčšieho množstva štruktúrovaných dát implementovať práve databázu typu SQLite.

Pre implementáciu SQLite databázy v aplikácii je využitá knižnica Room. Výhody, pre ktoré bola knižnica Room zvolená sú: výrazné skrátenie a sprehľadnenie kódu, validácia správnosti SQL príkazov už počas kompilácie, priama podpora knižnice RxJava.

Knižnica Room

Knižnica Room predstavuje abstraktnú vrstvu nad vrstvou SQLite databázy. Slúži pre vytvorenie databázy ako aj pre prístup k jej dátam.

Knižnica Room sprostredkováva mapovanie databázových relácií na objekty v jazyku Java na základe spracovávania anotácií. Anotácie sú špeciálne príkazy, ktoré sú v prípade knižnice Room priradené k definíciám tried, metód a premenných. Pri kompilácii Room na základe použitej anotácie vygeneruje Java kód, na ktorý sa prostredníctvom anotácií odkazuje. Tento spôsob práce je označovaný aj ako ORM (Object-Relational Mapping). V tejto časti je použitý zdroj informácii .

Množina tried pre vytvorenie SQLite databázy pomocou knižnice Room

Pre vytvorenie a prácu s SQLite databázou pomocou knižnice Room je potrebné implementovať základnú množinu Java tried: Entita, DAO a Databáza. Pri týchto triedach je potrebné použiť anotácie @Entity, @DAO, @Database.

@Entity - anotácia triedy, ktorá reprezentuje entitu databázy. Jednotlivé premenné triedy reprezentujú atribúty danej entity. K atribútom je potrebné umožniť prístup cez metódy get a set .

@DAO - (Data accessing object) anotácia rozhrania, ktoré obsahuje metódy pre prístup do databázy. Jednotlivé metódy majú priradené anotácie na základe SQL operácie, ktorú vykonávajú:

@Insert - vkladanie záznamov do databázy,

@Update - aktualizovanie existujúcich záznamov,

@Delete - mazanie záznamov,

@Query - alternatívna možnosť definovania vlastných SQL príkazov.

Parameterom týchto anotácií je textový reťazec reprezentujúci SQL príkaz, ktorý daná metóda vykonáva. Návratový typ metód DAO musí korešpondovať s výstupom SQL príkazu, ktorý daná metóda vykonáva .

@Database - anotácia triedy, z ktorej Room vytvorí databázu. Parameter anotácie musí obsahovať zoznam všetkých entít, resp. Java tried s anotáciou @Entity, ktoré majú byť transformované na entity databázy. Pri triede databázy je dôležité uplatnenie Singleton návrhového vzoru, ktorý zabezpečí vytvorenie a prístupnosť jedinej inštancie triedy databázy po celý čas behu aplikácie .

Ďalšie anotácie knižnice Room

Použitie nasledujúcich anotácií je nepovinné, avšak pri samotnej implementácii značne uľahčuje prácu s databázou. Tieto anotácie sa používajú ako anotácie premenných tried jednotlivých entít .

@PrimaryKey - anotácia premennej triedy entity, ktorá v databáze reprezentuje primárny kľúč. Voliteľný parameter tejto anotácie umožňuje explicitne zadeklarovať automatické generovanie primárneho kľúča (autoincrement).

@ForeignKey - umožňuje vytvorenie relácie medzi jednotlivými entitami pomocou cudzích kľúčov.

@ColumnInfo - ako parameter tejto anotácie je použitý textový reťazec, ktorý definuje názov atribútu, pod ktorým bude premenná triedy entity vložená do databázy.

@Ignore - anotácia, ktorú je možné použiť v prípade, ak má Room ignorovať danú premennú triedy, napr. nepoužiť premennú ako atribút entity v databáze.

Použitie knižnice Room demonštrujú ukážky priamo z jej implementácie v aplikácii v časti [implementacia_sql].

Práca s vláknami v systéme Android

Pri spustení Android aplikácie (nebežiacej na pozadí), vytvorí systém pre túto aplikáciu nový Linux proces, ktorý má pre svoj beh vyhradené jednovláknové operácie. Systémové nastavenie všetkých komponentov jednej aplikácie je také, že všetky bežia na jednom procesorovom vlákne nazývanom hlavné vlákno (main thread).

Úlohou hlavného vlákna je zabezpečiť responzívnosť a správne fungovanie používateľského rozhrania. Hlavné vlákno zodpovedá za delegovanie udalostí na jednotlivé View komponenty (tlačidlá, textové polia…). Všetky tieto komponenty bežiace na hlavnom vlákne musia byť neustále dostupné pre interakciu s používateľom aplikácie. To znamená, ak používateľ klikne na tlačidlo, musí mať hlavné vlákno dostatok pamäťových prostriedkov na spracovanie obsluhy tejto udalosti.

V prípade vykonávania iného, časovo náročnejšieho (blokujúceho) procesu na hlavnom vlákne, je hlavné vlákno zablokované, prestáva odpovedať a systém celý proces aplikácie ukončí. Z tohto dôvodu je potrebné časovo náročnejšie operácie vykonávať v inom, paralelnom tzv. pracovnom vlákne (worker thread) . Pre potrebu obsluhy časovo náročných operácií v paralelných vláknach je v aplikácii použitá knižnica RxJava.

Knižnica RxJava

RxJava je knižnica, ktorá umožňuje reaktívne resp. udalosťami riadené programovanie. Základný návrhový vzor využívaný touto knižnicou je Observer. Tento návrhový vzor funguje na princípe akcie a reakcie. Observer predstavuje objekt, ktorý sleduje stav iného objektu a v prípade zmeny stavu sledovaného objektu je Observer automaticky notifikovaný. Tento návrhový vzor je v knižnici RxJava využitý pri sledovaní priebehu asynchrónne vykonávanej práce na pracovných vláknach.

Práve možnosť asynchrónneho vykonávania operácií predstavuje jednu z najväčších predností knižnice RxJava. V nasledujúcej časti je použitý zdroj , pričom je zachovaná terminológia oficiálnej dokumentácie knižnice RxJava.

Spolupráca knižníc RxJava a Room

implicitne zakazuje prácu s SQLite databázou na hlavnom aplikačnom vlákne, pretože práca s databázou predstavuje časovo náročnejšie operácie. Z tohto dôvodu je nutné operácie spojené s SQLite databázou vykonávať asynchrónne.

  • Observable reprezentuje ľubovoľný objekt, ktorý môže získavať dáta z dátového zdroja (generuje hodnoty - metódy DAO) a ktorého stav môže byť sledovaný ďalšími objektmi (observers).
  • Observer predstavuje ľubovoľný objekt, ktorý sleduje stav Observable a má byť v prípade zmeny jeho stavu notifikovaný (prijíma hodnoty).

Vďaka vzájomnej kompatibilite knižníc RxJava a Room je možné použiť niektorú z tried knižnice RxJava ako wrapper (obal) návratového typu metódy DAO. Použitím niektorej observable triedy knižnice RxJava ako wrapper návratového typu metódy DAO, môže byť následne celá práca tejto metódy presmerovaná na pracovné vlákno aplikovaním RxJava operátorov pre asynchrónnu prácu.

Základné observable triedy knižnice RxJava

  • trieda Single - Observable, ktorá vracia buď jeden objekt alebo chybu.
  • trieda Completable - Observable, vracajúca len výsledok operácie vo forme informácie, či bola úloha dokončená, alebo prišlo k chybe, samotné dáta nevracia.
  • trieda Maybe - Observable, ktorá podobne ako Single vracia jeden objekt, ale nemusí žiaden. Na rozdiel od Single nevyhlási chybu a vráti prázdnu hodnotu.

Príklad použitia observable triedy Maybe demonštruje [listing:dao], z jej implementácie priamo v aplikácii.

Operátory knižnice RxJava pre asynchrónne vykonávanie operácií

Operátory knižnice RxJava slúžia nielen na zadefinovanie pracovného vlákna, na ktorom sa bude asynchrónna práca (metóda) vykonávať, ale aj na špecifikáciu vlákna, ktoré má prijímať výsledky generované týmto pracovným vláknom. Medzi tieto operátory patria: subscribeOn(), observeOn(), subscribe().

Operátor subsribeOn()

Tento operátor slúži na definovanie vlákna, v ktorom sa má práca metódy, na ktorú je operátor subscribeOn() volaný vykonať. Ako parameter operátora subscribeOn() môžeme použiť triedu Schedulers, ktorá disponuje metódami io(), computation(), single() a iné. Každá z týchto metód slúži pre definovanie špecifického vlákna, na ktorom bude práca metódy, na ktorú je operátor subscribeOn() aplikovaný vykonávaná . Každé z týchto vlákien má svoj špecifický účel :

  • computation() - sprístupňuje vlákno určené pre komplikovanejšiu, časovo náročnejšiu výpočtovú prácu. Maximálny počet spustených vlákien metódou computation() je limitovaný počtom procesorov.
  • io() - sprístupňuje vlákno určené pre I/O prácu, tzn. vlákno pre asynchrónne vykonávanie inak blokujúcej I/O práce. Umožňuje vytvoriť ľubovoľný počet potrebných vlákien.
  • single() - sprístupňuje jediné zdielané vlákno. Toto vlákno je určené pre operácie, ktoré majú byť vykonávané výhradne sekvenčne na jednom a tom istom zdielanom vlákne na pozadí.

Operátor subsribe()

Operátor, ktorý spája observera spolu s Observable tak, že sprostredkováva observerovi výsledky generované Observable objetkom. Aby observer mohol vidieť jednotlivé objekty generované Observable, alebo dostať informáciu o tom, či operácia skončila úspešne alebo chybou, musí byť najskôr na Observable pripojený práve použitím metódy subscribe(). Operátor subscribe() prijíma ako parameter objekt (nazývaný Observer alebo Subscriber), ktorý implementuje rozhranie obsahujúce niektorú z týchto metód :

  • onNext() - Observable volá túto metódu vždy, ak publikuje nový objekt. Parameter metódy je práve publikovaný objekt.
  • onError() - Observable zavolá túto metódu, ak dôjde k chybe pri generovaní objektov očakávaných metódou onNext(). Pri zavolaní metódy onError(), je Observable zastavený a nepríde k ďalším volaniam metód onNext() a onComplete().
  • onCompleted() - Observable zavolá túto metódu, ak je metóda onNext() zavolaná poslednýkrát a nenastala žiadna chyba.

Operátor observeOn()

Ak použijeme operátor subsribeOn(), práca Observable je presmerovaná na v ňom definované pracovné vlákno. Použitím operátora observeOn() špecifikujeme iné vlákno, v ktorom má byť po dokončení práce notifikovaný observer.

Operátor observeOn() určuje vlákno, na ktoré má Observable prostredníctvom operátora subscribe() publikovať výsledky. Zabezpečuje presmerovanie výsledku prúdu z pracovného vlákna definovaného v operátore subscribeOn() na vlákno definované v operátore observeOn(). Ako parameter observeOn() operátora môžeme špecifikovať napríklad hlavné vlákno použitím triedy AndroidSchedulers a jej metódy mainThread() . Príklad použitia operátorov RxJava priamo v aplikácii demonštruje [listing:rx_operators].