Sam svoj programer
Nadaljujemo s serijo člankov "Programiranje za Android". V prvem smo si ogledali, kako vzpostaviti razvojno okolje in kako narediti enostavno aplikacijo "Pozdravljen, svet!" S tem smo naredili prvi korak v svet razvoja aplikacij za platformo Android. V pričujočem članku se bomo podrobneje seznanili z androidno platformo in tem, kaj vse nam omogoča androidni vmesnik API. Prav tako bomo razvili novo aplikacijo, ki bo na zaslonu prikazala izbrano sliko, ki jo bomo upravljali z dotikanjem zaslona.
Za lažji razvoj se je treba podrobneje seznaniti s platformo Android, njenimi sestavnimi deli in tem, kaj vse omogoča razvijalcu. Z novejšimi različicami se je platforma nadgrajevala, dopolnjevala, odpravljenih je bilo tudi veliko hroščev in nerodnih pristopov. Prav tako so novejše različice platforme prinesle podporo vse večjemu naboru naprav, na katerih lahko sistem teče, pa tudi vse večjemu naboru podprtih dodatnih naprav (kamere, bralniki kartic, brezžična omrežna povezava, moduli GPS, bluetooth komunikacija, podpora zunanjim miškam in tipkovnicam ...). Trenutno najnovejša različica omogoča razvoj lastnih gonilnikov za poljubne naprave USB, s čimer si je platforma še dodatno razširila tržno zanimivost.
Platforma Android
Android je brezplačna odprtokodna mobilna platforma, ki jo je Google splavil leta 2005, ko je prevzel istoimensko podjetje in nadaljeval razvoj mobilnega operacijskega sistema, temelječega na sistemu Linux. Google je platformo predstavil novembra 2007. Mobilna platforma Android vključuje operacijski sistem, uporabniške vmesnike, posredniški sistem in osnovne aplikacije. Namen platforme je olajšati razvoj aplikacij na področju mobilnih naprav, hitrejšo uvedbo izdelkov na trgu in nižje stroške razvoja programske opreme z vzpodbujanjem razvijalske skupnosti. Glavni poudarek platforme je prav na preprostem razvoju uporabniških aplikacij, še posebej takih, ki uporabljajo spletne storitve.
Platforma Android ima popolno programsko podporo zamenljivosti strojnih komponent mobilne naprave, s čimer ponuja podporo širokemu naboru naprav različnih znamk. Sistem podpira uporabo jave prek t. i. navideznega stroja Dalvik (DVM), ima integriran spletni brskalnik, ki temelji na odprtokodnem spletnem stroju WebKit, optimizira grafični izris z možnostjo strojnega pospeševanja, vsebuje vgrajeno zbirko podatkov SQLite, vgrajena je podpora prikazu in predvajanju večpredstavnih vsebin ... Ob tako pestri podpori ni čudno, da je platforma tako priljubljena tako pri izdelovalcih mobilnih naprav kot pri končnih uporabnikih.
Arhitektura
Sistem Android je sestavljen iz šestih osnovnih komponent: aplikacije, aplikacijskega ogrodja, knjižnice, zagonskega okolja in linuxnega jedra. Prikazane so na sliki 1.
Že s samim sistemom uporabnik dobi osnovni nabor aplikacij, ki jih posamezni izdelovalci velikokrat dodatno razširijo in prilagodijo svojim zahtevam. Med njimi so aplikacije, kot so odjemalec elektronske pošte, aplikacija SMS, koledar, zemljevidi, brskalnik, imenik in druge. V to komponento sistema sodijo tudi aplikacije, ki jih uporabnik sam prenese z androidne tržnice, iz spleta ali jih kako drugače naloži na svojo napravo. Te aplikacije so napisane v programskem jeziku java in za svoje delovanje uporabljajo aplikacijsko ogrodje.
Slika prikazuje glavne komponente sistema Android. (Vir: developer.android.com)
Tako kot aplikacije je tudi celotno aplikacijsko ogrodje napisano v programskem jeziku java in vsebuje nabor osnovnih komponent, ki jih uporabljajo vse aplikacije med svojim delovanjem. To velja seveda tudi za vse sistemu priložene aplikacije. Podrobnejša sestava aplikacijskega ogrodja je:
Knjižnice
Poleg aplikacijskega ogrodja vsebuje Android še zbirko programskih knjižnic, namenjenih uporabi različnih delov samega sistema. Nabor knjižnic obsega:
Androidno zagonsko okolje
Glavni del zagonskega okolja Android je navidezni stroj Dalvik, zasnovan in narejen posebej za uporabo v sistemu Andorid z namenom izpolnjevanja zahtev za delovanje v vgrajenem načinu, kjer so omejitve napajanja (zmogljivost baterije), procesorske moči in omejena velikost pomnilnika.
Vsaka androidna aplikacija se izvaja v svojem procesu v svoji instanci navideznega stroja Dalvik, ki je posebej prirejen za boljše delovanje z več vzporedno pognanimi instancami. Datoteke, ki jih poganja navidezni stroj Dalvik, so optimizirane za minimalno zaseganje sistemskih virov in so v resnici dodatno optimizirane javanske zagonske datoteke. Navidezni stroj izkorišča nizkonivojske funkcionalnosti linuxnega jedra za čim boljšo izrabo paralelizma in čim manjšo porabo sistemskih virov.
Naslednji višji nivo predstavljajo jedrne knjižnice (Core Libraries) v programskem jeziku java, ki predstavljajo zbirko vseh razredov, pripomočkov in vhodno/izhodnih vmesnikov, ki jih potrebujemo pri razvoju aplikacij.
Slovarček
dedovanje - postopek, kjer določen razred uporablja metode razreda, ki ga razširja (glej razširjanje).
DVM - Dalvik Virutal Machine ... navidezni stroj Dalvik, ki v Androidu nadomešča originalni javanski navidezni stroj za poganjanje aplikacij. Za razliko od osnovnega javanskega navideznega stroja je prilagojen poganjanju na manj zmogljivih mobilnih napravah.
float - tip števila, ki omogoča hranjenje števil z decimalno vejico v enojni natančnosti.
inicializacija - postavljanje vrednosti spremenljivke na začetno vrednost.
konstruktor - metoda razreda, ki se izvede ob stvaritvi novega primerka razreda. Metoda se uporablja za določanje začetnih lastnosti predmeta.
nadrazred - razred, ki je pri definiranju novega razreda osnova, ki jo razširjamo. Tako definiranemu razredu pravimo tudi izpeljani razred, procesu pa dedovanje. Vsak izpeljani razred vsebuje vse metode nadrazreda, ki jih lahko poljubno redefiniramo, poleg teh pa lahko vsebuje še dodatne metode.
parameter metode - podatek, ki ga kot vhod prejme neka metoda in ga uporabi med izvajanjem.
razširjanje - postopek, kjer pri ustvarjanju novega razreda za "šablono" uporabimo obstoječi razred in mu dodamo novo funkcionalnost ali spremenimo obstoječo.
spremenljivka - oznaka v kodi, ki jo uporabljamo za dostop in delo s predmeti in podatki enostavnih tipov. Eno spremenljivko lahko priredimo tudi drugi spremenljivki. Priredba v programski kodi vedno velja od desne proti levi, na primer int a = 5 (a tipa celo število naj shrani vrednost 5).
Življenjski cikel aplikacije
Vsaka androidna aplikacija je lahko sestavljena iz štirih možnih komponent:
Pri večini preprostih aplikacij se največkrat uporabljata aktivnost in storitev, v našem primeru pa bomo potrebovali zgolj aktivnost, ki je podrobneje predstavljena v nadaljevanju.
Aktivnost
Kot smo pri pregledu programske kode lahko opazili že v prejšnjem članku, se androidne aplikacije praviloma zaženejo kot aktivnosti. Aktivnost je ena izmed možnih komponent aplikacije in edina možnost, da aplikacijo poženemo z uporabniškim vmesnikom, drugi načini so primerni predvsem za poganjanje aplikacij v ozadju in se z njimi v začetni fazi ne bomo srečali. Koncept aktivnost predstavlja posamezni zaslon aplikacije z uporabniškim vmesnikom, na primer seznam prejetih sporočil, druga aktivnost lahko vsebuje vsebino sporočil, tretja pa na primer izbiro prejemnika posameznega sporočila. Kljub temu da aktivnosti praviloma medsebojno usklajeno podajajo zvezno uporabniško izkušnjo, so med seboj ločene in lahko do posamezne aktivnosti pridemo po različnih scenarijih. Do sestave sporočila lahko pridemo prek aktivnosti kamere, ko želimo fotografijo deliti s prijateljem. Tako se lahko aktivnosti prožijo iz različnih komponent aplikacije, lahko pa jih prožijo tudi druge aplikacije. V določenih primerih lahko aktivnost vrača tudi vrednost.
Med preklopom aktivnosti se aktivnost, ki je imela trenutno nadzor nad zaslonom, neha izvajati in jo sistem potisne v t. i. zgodovinski sklad ter s tem ohrani notranje stanje aktivnosti za kasnejše nadaljevanje izvajanja. Aktivnosti se lahko iz sklada tudi odstrani v primeru nesmiselnega shranjevanja stanja ali pomanjkanja pomnilnika.
Linuxno jedro
Samo osrčje Androida predstavlja linuxno jedro, ki zagotavlja varnost, upravljanje pomnilnika, upravljanje procesov, omrežni sklad in model gonilnikov. Linuxno jedro predstavlja nekakšno abstrakcijo med strojno opremo in programskim skladom, njegovi odliki pa sta zanesljivost in robustnost.
Stanja aktivnosti
Aktivnost je v vsakem trenutku v enem izmed štirih možnih stanj:
Prehodi med stanji
Androidna platforma omogoča zaznavanje prehoda med posameznimi stanji aktivnosti s pomočjo posebnih metod razreda Activity, ki jih sistem ob prehodih med stanji avtomatsko kliče. Te metode so:
void onCreate(Bundle savedInstanceState)
void onStart()
void onRestart()
void onResume()
void onPause()
void onStop()
void onDestroy()
Prazne implementacije teh metod so že del razreda Activity, obvezno je implementirati le metodo onCreate, ki se kliče ob samem proženju aktivnosti. Če programer ne določi drugače, so prehodi med posameznimi stanji aktivnosti pri izvajanju aplikacije "nevidni", ob redefiniciji določenih metod pa lahko te prehode naredimo tudi vidne z izvedbo določenih akcij (sprememba vsebine). Z možnostjo redefinicije metod se imamo možnost odzvati na spremembe ob določenih dogodkih. Tako lahko ob koncu aktivnosti trajno shranimo uporabnikov vnos. POZOR: Pri redefiniranju metod je treba vedno najprej klicati metodo nadrazreda! Spodaj je podan primer redefiniranja metode onPause.
public void onPause() {
super.onPause();
// ko aplikacija ni vec aktivna ne potrebujemo vec
// sprotnega spremljanja trenutne lokacije
locationManager.removeUpdates(locationListener);
}
Kako so med seboj povezana posamezna stanja, v katerih je lahko aktivnost, je prikazano na sliki 2, ki vsebuje t. i. življenjski cikel aktivnosti.
Življenjski cikel aktivnosti (Vir: developer.android.com)
Prikažimo sliko
V naslednjem programerskem koraku se bomo spopadli s prikazom slike v aplikaciji in spreminjanjem njenega položaja na mesto, kjer se dotaknemo zaslona. Nalogo bomo razdelili na tri dele. V prvem delu bomo v aplikaciji prikazali izbrano sliko, v drugem delu bomo pridobili lokacijo dotika, v tretjem pa bomo oboje združili v končni rezultat. Nadgradimo lahko kar projekt, ki smo ga ustvarili v okviru prejšnjega članka, ali na enak način ustvarimo nov projekt.
Prvi del - prikaz slike
Sliko lahko v aplikacijo dodamo na več načinov. Najpreprostejši je ta, da sliko dodamo med vire, vključene v aplikacijo, pri čemer nam ni treba dodatno skrbeti za prenašanje v pomnilnik mobilne naprave. V tem primeru je slika v aplikaciji dostopna prek razreda virov - R. Drugačen pristop je na primer branje slike neposredno z datotečnega sistema, kar pri izdelavi naše igrice ni relevantno. Na tem mestu velja omeniti še to, da androidna platforma podpira naprave z različnimi gostotami slikovnih pik na zaslonu in omogoča samodejno izbiro virov, ki so za določeno napravo najprimernejši. Tako lahko med vire aplikacije dodamo tudi slike različnih ločljivosti, ki so namenjene uporabi na različnih napravah (telefoni ali tablice). Za vključene slikovne elemente so tako v projektu znotraj mape res na voljo mape drawable-hdpi, drawable-ldpi in drawable-mdpi. Če želimo pri vseh napravah uporabljati iste slikovne vire, jih enostavno dodamo v mapo drawable, ki jo je treba v večini primerov ustvariti ročno (z desnim mišjim gumbom kliknemo mapo res v Package Explorerju, nato izberemo možnost New->Folder in mapo ustrezno poimenujemo). Prav tako naj opomnimo, da je vire nujno poimenovati z malimi črkami in številkami, brez posebnih znakov. Če boste imeli vire z drugačnimi imeni, boste v projekt vnesli napake. V našem primeru bomo v mapo drawable prekopirali sliko 3 (v našem imenu smo jo poimenovali slika3.jpeg), ki prikazuje vesoljskega napadalca.
Vesoljski napadalec, glavni junak igre Space invaders
Za potrebe prikaza slike na točno določenem mestu zaslona bomo ustvariti nov razred, ki razširja obstoječi razred View. Razred bomo poimenovali GameView, saj bomo dopolnjeni razred kasneje uporabili za prikaz večine grafičnih elementov naše igre. Nov razred ustvarimo tako, da v Package Explorerju izberemo paketek (fri.lgm.android), ga kliknemo z desnim mišjim gumbom, izberemo New->Class in nov razred ustrezno poimenujemo. V novem razredu je treba definirati zasebne spremenljivke razreda in metode. Programska koda za razred GameView je dostopna na android.monitor.si.
Na tem mestu bomo opisali namen posameznih spremenljivk in metod razreda GameView. V prvi vrstici je naveden paket, v katerem je razred. V nadaljnjih vrsticah je z rezervirano besedo import naveden uvoz drugih potrebnih paketov, za pravilno prevajanje programske kode. Sledi definicija razreda GameView, kjer navedemo tudi, kateri razred (View) razširjamo z rezervirano besedo extends. Znotraj razreda definiramo zasebne spremenljivke, ki jih bomo uporabili za hranjenje objetov Paint (razred, ki hrani informacije o izrisu) in Bitmap (razred, namenjen hranjenju informacij o bitni sliki) ter za hranjenje položaja slike na zaslonu (dve števili tipa float). Sledijo metode: GameView (konstruktor razreda), v kateri posredujemo kontekst nadrazredu in sprožimo inicializacijo spremenljivk; metoda initGameView, ki inicializira spremenljivke razreda (ustvari nove instance objektov Paint in Bitmap, v slednjega naloži tudi sliko vesoljskega napadalca); metoda onDraw prepiše isto imensko metodo nadrazreda (kar je označeno z @Override) in poskrbi za izris slike na platno (in s tem tudi na zaslon); metoda setPosition nastavlja zasebne spremenljivke, ki določajo položaj izrisa vesoljskega napadalca.
S tem, ko smo naredili nov razred, ki razširja razred View, smo naredili novo komponento, ki jo lahko dodamo v uporabniški vmesnik naše aplikacije. Grafični uporabniški vmesnik (GUI) aplikacije je definiran v datoteki main.xml znotraj mape res->layout znotraj projekta. Ko datoteko odpremo, lahko GUI sestavimo s pomočjo posameznih komponent, lahko pa ga v obliki formata XML definiramo tudi ročno (med načinoma preklopimo z jezički na spodnji strani). Na levi strani urejevalnika je paleta komponent. Na zavihku Custom & Library Views je prikazan tudi pogled, ki smo ga definirali z razredom GameView. V osnovnem uporabniškem vmesniku je že dodan tekstovni pogled (TextView) z napisom "Hello World ..." Ta tekstovni pogled bomo v našem primeru odstranili in ga nadomestili z našo GameView komponento. To storimo tako, da pogled označimo z miško in pritisnemo tipko Delete. V uporabniški vmesnik moramo v naslednjem koraku dodati naš pogled GameView. To storimo tako, da komponento zagrabimo na paleti na levi strani in jo prenesemo v vmesnik na desni. V nadaljevanju bomo spremenili še ikono, kar je podrobneje opisano na android.monitor.si. Končni videz vmesnika je prikazan na sliki 4.
Zaslonski posnetek urejevalnika grafičnega uporabniškega vmesnika z dodano komponento GameView in spremenjeno ikono programa.
Drugi del - zaznava dotika
V drugem delu bomo implementirali poslušalca, ki se odziva na dotike zaslona touchListener. Implementacijo poslušalca bomo realizirali kot zasebni razred v naši aktivnosti. To prikazuje spodnja koda:
private OnTouchListener touchListener = new OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
int action = event.getAction();
switch (action) {
case MotionEvent.ACTION_DOWN:
case MotionEvent.ACTION_MOVE:
((GameView)v).setPosition(event.getX(), event.getY());
v.postInvalidate();
break;
}
return true;
}
};
Pri realizaciji poslušalca je treba redefinirati metodo onTouch, ki se izvede ob vsakem zaznanem dotiku zaslona. V tej metodi preverimo, za kakšno akcijo gre. V našem primeru preverimo, ali gre za akcijo dotika (ACTION_DOWN) ali premika (ACTION_MOVE) na površini. V obeh primerih se odzovemo enako, s premikom slike na zaznani položaj. V obeh primerih nastavimo položaj vesoljskega napadalca. Treba je še razveljaviti veljavnost pogleda, s čimer sprožimo njegov vnovični izris.
Android API
Množico paketov, namenjeno olajšanju razvoja aplikacij, imenujemo Android API. Takšne množice paketov so značilne za večino programskih jezikov. Za Android API velja, da vključuje veliko paketov, ki se uporabljajo enako kot njihovi ustrezniki v javi. Kateri paketi Java APIja so vključeni in kateri so preostali paketi v APIju, najdete tudi na spletni strani android.monitor.si.
Tretji del - združitev
Za konec moramo samo še ustrezno spremeniti razred aktivnosti (če nadgrajujete nalogo iz prejšnjega članka, to pomeni razred And_PozdravljenSvetActivity). V razredu je treba popraviti skoraj večino funkcionalnosti. Najprej moramo aktivnosti zopet dodati vrstico kode, ki določa, da aktivnost za urejanje vmesnika uporablja razporeditev, definirano v datoteki main.xml. Vsebina metode onCreate je prikazana spodaj.
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
GameView myView = (GameView)findViewById(R.id.gameView1);
myView.setFocusable(true);
myView.setFocusableInTouchMode(true);
myView.requestFocus();
myView.setOnTouchListener(touchListener);
}
V kodi najprej v spremenljivko myView pridobimo referenco na GameView, ki smo ga dodali v uporabniški vmesnik aplikacije. Pogledu (GameView) določimo sposobnost sprejema fokusa in možnost sprejema fokusa v primeru dotika. V naslednjem koraku zahtevamo fokus nad našim pogledom, s čimer pogled aktiviramo. Temu sledi dodajanje poslušalca touchListener na naš pogled, s čimer omogočimo, da se poslušalec odziva na dotike našega pogleda. Na sliki 5 je prikazan končni videz zagnane aplikacije. Celotna koda je dosegljiva na android.monitor.si.
Zaslonski posnetek končne aplikacije
Nadaljevali bomo z ...
V drugem delu serije smo se posvetili samemu delovanju androidne platforme in njeni zgradbi. Ogledali smo si, kakšen je življenjski cikel aplikacije in življenjski cikel najpogostejše oblike androidne aplikacije - aktivnosti. Razvili smo eno aplikacijo, ki je korak dlje na poti k izvedbi končne igrice. Med razvojem smo se srečali s problemi, kako v aplikacijo uvoziti svojo sliko in kako jo premikati na mesto dotika. V naslednjem delu si bomo pogledali še nekaj podrobnosti delovanja platforme in razvili enostavno aplikacijo - galerijo slik naše vesoljske ladje in sovražnikov ter dodali animacije pri premikanju slik po zaslonu.