117169381-Mala-škola-Androida-VIDI
October 20, 2017 | Author: jalija | Category: N/A
Short Description
Android...
Description
Mala škola Androida by Vidi android.vidilab.com
RIPed by: Memhis (12/2012)
Sadržaj: 1. Priprema razvojne okoline za pisanje Google Android aplikacija 2. Pisanje i pokretanje prvog programa 3. Interakcija s korisnikom 4. Uvod u pisanje programskoga koda 5. Korištenje rasporeda kontrola u složenim aplikacijama 6. Korištenje osnovnih Android kontrola 7. Android programiranje 8. Android kontrole u akciji IV 9. Korištenje datotečnog sustava 10. Nekoliko standardnih dijelova aplikacije 11. Standardni dijelovi aplikacije 12. Alternativni pristup razvoju aplikacija 13. Alternativni pristup razvoju aplikacija II 14. Alternativni pristup razvoju aplikacija III 15. Izrada složenijih aplikacija 16. Korištenje kartografskih servisa 17. Što je novo u 3.x izdanjima
1. Priprema razvojne okoline za pisanje Google Android aplikacija Želimo li programirati za platformu Google Android najprije na računalo trebamo instalirati i konfigurirati razvojne alate. Već na tom koraku mnogi odustaju, jer se za razvoj koriste tri različita alata, a svaki od njih ima drugačijeg proizvođača. Da bi sve proradilo kako treba, instalaciju treba napraviti baš „prema propisima“. Krenimo redom, uz jednu bitnu pretpostavku. Postupak instalacije opisan je za „čisto“ Windows računalo, što znači da je na njemu instaliran samo operativni sustav, bez neke od starijih inačica alata koje ćemo spomenuti u nastavku. Na računalu nisu pokrenuti ni svakakvi antivirusni programi, vatrozid ili slični programi, jer bi oni mogli blokirati neke od opisanih postupaka. U takvom slučaju ne možemo pretpostaviti svaku moguću situaciju u praksi, odnosno objasniti kako riješiti nastali problem, pa zato preporučujemo da postupak započnete od nulte konfiguracije sustava. Kao što smo to već ranije spomenuli, na računalo treba instalirati tri razvojna alata različitih proizvođača. Iako sve može proraditi i ako se ne koriste baš inačice s identičnim oznakama na „zadnju decimalu“, nego neke druge brojčano slične inačice, preporučujemo vam da koristite isključivo one opisane u nastavku teksta jer s njima sve sigurno i provjereno radi. Osim toga, sva tri alata dostupna su na DVD‐u travanjskog broja časopisa VIDI, ukoliko ne želite gubiti vrijeme na njihovo preuzimanje s weba. Alate treba instalirati ovim redoslijedom: 1. jdk‐6u17‐javafx‐1_2_1‐windows‐i586.exe 2. eclipse‐java‐galileo‐SR2‐win32.zip 3. android‐sdk_r04‐windows.zip Datoteka jdk‐6u17‐javafx‐1_2_1‐windows‐i586.exe Sunov je razvojni alat za Java aplikacije pod oznakom Java SE Development Kit 6 Update 17. U toj datoteci nalazi se Sunov razvojni alat za RIA aplikacije s oznakom JavaFX 1.2 SDK. Kad već morate instalirati Javu kao preduvjet za pisanje Google Android aplikacija, zašto ne biste instalirali i razvojni alat za RIA aplikacije istog proizvođača? Možda vam nekad zatreba nešto takvo, iako JavaFX SDK nije preduvjet za razvoj Android aplikacija. Instalacija Sunovog proizvoda najviše liči na instalaciju profesionalnog razvojnog alata na kakvu ste vjerojatno navikli, pa je zato nećemo ni posebno opisivati, jer je doista riječ o trivijalnom postupku. Dovoljno je pokrenuti prije spomenutu datoteku te jednostavno prihvatiti sve podrazumijevane postavke instalacije. Jedini izuzetak mogla bi biti činjenica da na podrazumijevanom disku nemate dovoljno prostora, ali odgovarajuća korekcija zaista ne bi trebala stvoriti previše problema kod instalacije. Za instalaciju druge datoteke eclipse‐java‐galileo‐SR2‐win32.zip, potreban vam je neki od alata za raspakiravanje zip datoteka, na čije ste korištenje vjerojatno navikli, pa ni tu nećemo gubiti previše prostora na opisivanje postupka rapakiravanja. Rezultat raspakiravanja jest mapa eclipse zajedno s pripadajućim podmapama. Mapu možete „objesiti“ izravno na korijensku mapu \, ili je staviti na za to uobičajeno mjesto C:\Program Files. U navedenoj mapi nalazi se izvršna datoteka eclipse.exe na
koju nakon toga možete napraviti prečac na radnoj površini operativnog sustava, kako biste je što jednostavnije pokretali tijekom budućeg korištenja. Objasnimo ukratko što je to zapravo Eclipse? Riječ je o vrlo naprednoj razvojnoj okolini za pisanje različitih vrsta aplikacija, a upravo je tu razvojnu okolinu predvidio i Google za razvoj Android aplikacija. Za sada o njoj samo toliko, a nešto više detalja o korištenju navest ćemo u budućim nastavcima kad nam zatrebaju različite mogućnosti razvojne okoline u pisanju aplikacija.
Prve komplikacije Kod trećeg koraka nastupaju komplikacije. Googleov razvojni alat nalazi se također u ZIP obliku pa ga kao i Eclipse treba prvo otpakirati. Kao rezultat dobiva se mapa android‐sdk‐windows. Njezino mjesto odaberite na isti način kao u prethodnom koraku. U ovom slučaju potrebno je napraviti još jednu dodatnu operaciju, a to je postavljanje varijable operativnog sustava Path, tako da pokazuje na tu mapu. I ovo bi trebao biti postupak poznat nešto iskusnijim korisnicima Windowsa, dok one manje iskusne upućujemo na prvu prateću sliku uz tekst koja pokazuje kako se taj postupak izvodi u hrvatskoj inačici Windowsa 7. Druga slika pokazuje istu stvar u engleskoj inačici. Ukratko, treba otvoriti upravljačku ploču Windowsa (Control Panel) te u njoj pronaći opciju namijenjenu dodatnom podešavanju parametara operativnog sustava, kao što su performanse sustava (uključujući virtualnu memoriju), korisnički profili i slično. Na tom mjestu nalazi se gumb za podešavanje varijabli okruženja (Environment Variables). Nakon otvaranja istoimenog dijaloškog okvira u popisu sistemskih varijabli, treba pronaći varijablu Path te u nju uključiti putanju do mape android‐sdk‐windows. U slici na primjeru to je napravljeno na samom početku varijable.
Zajednički jezik Ako je do sada sve prošlo bez problema, na računalo su instalirana sva tri osnovna alata, ali smo još prilično daleko od pisanja prvih aplikacija. Treba napraviti još nekoliko dodatnih koraka kako bi se sva tri alata međusobno „razumjela“ te tako doista omogućila stvaranje vlastitih Android aplikacija. Krenimo kroz novi niz koraka u konfiguriranju sustava. Prvo treba pokrenuti Eclipse. Kod prvog pokretanja razvojne okoline bit će zatraženo da izaberemo neku mapu na disku koja će u budućnosti služiti kao radni prostor za druge projekte. Možemo izabrati mapu poput C:\workspace, ili nešto drugo prema vlastitom nahođenju. Nakon toga otvara se glavni prozor razvojne okoline u kojem treba izvesti sljedeći niz koraka da bi se Eclipse povezao s Google Android sustavom.
1. Za početak u razvojnoj okolini treba izabrati naredbu Help > Install New Software…
2. U dijaloškom okviru Install, koji se otvara nakon toga, treba kliknuti na gumb Add.
3. Kao rezultat prethodne operacije, otvara se dijaloški okvir Add Site s okvirima Name i Location. U prvi okvir treba upisati nešto što će označavati o kakvim je dodacima za Eclipse riječ – na primjer, Android dodaci ili Android Plugin. U drugo polje (Location) treba upisati sljedeći tekst: https://dl‐ssl.google.com/android/eclipse/
4. Nakon toga treba kliknuti na gumb OK.
5. Nakon povratka na prethodni dijaloški okvir, trebali biste vidjeti oznaku novog dodatka. Na ovom dijaloškom okviru označite okvir Developer Tools, a onda preostaje dva puta kliknuti na gumb Next te završiti prvi dio podešavanja radne okoline. Napomena: Vrijeme koje je potrebno da razvojna okolina „posloži“ sve što treba nakon prvog pritiska na gumb Next može biti prilično dugo (ovisno o brzini računala i vezi na Internet, to može potrajati čak desetak minuta). Nemojte nikako na silu prekidati postupak, jer je sve u redu, samo što zbog nekog razloga sve traje poprilično dugo. Na kraju ovog koraka treba još prihvati uvjete korištenje licence, a onda kliknuti na gumb Finish. 6. Sada izađite iz razvojne okoline Eclipse pa je nakon toga ponovno pokrenite. U slučaju da prije svoga zatvaranja razvojna okolina želi napraviti određena ažuriranja vlastitih postavki, strpljivo sačekajte da se dovrši i taj postupak. 7. Nakon ponovnog otvaranja razvojne okoline, izaberite naredbu izbornika Windows > Preferences kako biste otvorili dijaloški okvir Preferences. Na prikazanom popisu u lijevoj strani prozora treba pronaći vrijednost Android, a onda na desnoj strani u okvir SDK Locations upisati (ili izabrati) putanju do Google Android SDK paketa te potvrditi odabir pomoću gumba OK.
8. Konačno smo stigli i do posljednjeg koraka u podešavanju, ali će on nažalost vremenski potrajati kao svi prethodno nabrojani koraci, počevši od instalacije Sunovog paketa. Potrebno je izabrati naredbu Windows > Android SDK and AVD Manager. Kao rezultat izvođenja prethodne operacije, otvara se istoimeni dijaloški okvir s prikazom dostupnih te trenutno instaliranih inačica Androida. Kako na početku nije instalirana još ni jedna inačica paketa, izaberite sve koje želite koristiti u praksi te prihvatite njihovu instalaciju pomoću gumba Install Selected.
Nakon dovršetka ovog koraka, vaše računalo konačno je spremno za razvoj Google Android aplikacija jer su na njemu svi potrebni sistemski moduli, a što je najvažnije, sada se konačno i međusobno razumiju. To možete provjeriti tako da u razvojnoj okolini Eclipse izaberete naredbu File > New > Project. Nakon toga, u dijaloškom okviru New Project trebali biste moći započeti Android Project, dok biste u sljedećem dijaloškom okviru New Android Project trebali moći izabrati razvoj aplikacija u različitim inačicama Androida.
Važna napomena za kraj. Ako namjeravate na vlastito računalo u koraku 8 izabrati instalaciju svih inačica Androida, onda se trebate naoružati popriličnom dozom strpljenja. Najbolje je da potvrdu preuzimanja svih inačica „okinete“ prije početka nekakve dobre nogometne ili bar rukometne utakmice, jer čitav postupak traje beskrajno duuuuuugooooooo. Ne nije nikakva šala. Baš kad završi utakmica lige prvaka, instalacija će biti dovršena. Na ovaj detalj upozoravamo vas zato što bi većina korisnika nenavikla na tako dugo vrijeme odziva računala na zadanu operaciju vjerojatno nasilno prekinula korak 8, a zapravo je sve u redu. Jednostavno nema pomoći – morate sačekati da se postupak završi kako biste mogli početi s pisanjem vlastitih aplikacija.
2. Pisanje i pokretanje prvog programa Prošli put smo u malo podužem početnom tekstu objasnili zašto pokrećemo novu školu programiranja i koji su nam sve alati potrebni za nju, odnosno kako ih treba instalirati na računalo da bi sve proradilo na odgovarajući način. Budući da je za razvoj Google Android aplikacija potrebno instalirati nekoliko alata različitih proizvođača, takva instalacija nikad ne prolazi tako glatko kao kad je riječ o instalaciji pojedinačnoga razvojnog alata samo jednog proizvođača. Ok, ako ste napravili sve što smo napisali u prošlom nastavku, sad biste trebali imati računalo spremno za pisanje prvog Google Android programa, što ćemo doista i napraviti u nastavku teksta. Usput ćemo malo „zagrepsti“ po glavnim dijelovima razvojne okoline potrebnim za razvoj takve vrste aplikacija, kao i samom emulatoru odgovarajućeg hardverskog uređaja, jer na kraju krajeva, tek u njemu možemo vidjeti rezultate rada našeg programa na smisleni način. Nakon toga se u sljedećim brojevima možemo pozabaviti samim programiranjem i naprednijim programskim tehnikama.
Stvaranje projekta HelloWorld: Ovako izgleda početni dijaloški okvir kod stvaranja projekta Kako rezervirani prostor za ovaj serijal u nekoliko brojeva časopisa jednostavno nije dovoljan za detaljnije bavljenje razvojnom okolinom, tog segmenta razvoja aplikacije dotaknut ćemo se samo kad nešto postane zaista neophodno. Ipak, ako ste do sad već koristili neku od modenijih razvojnih okolina za razvoj aplikacija (a napomenuli smo da praćenje serijala zahtijeva određeno predznanje), onda ne biste trebali imati previše problema ni sa snalaženjem u razvojnoj okolini Eclipse. Kao što to dobra programerska tradicija nalaže, priču o programiranju u Google Androidu započet ćemo od trivijalnog HelloWorld primjera. Njegova namjena jest pokazati kako se u novom razvojnom okruženju prikazuje jednostavna poruka korisniku programa. Za mlađe (ili starije) čitatelje koji možda upravo sada prvi put započinju avanturu programiranja u nekom programskom jeziku, treba napisati samo kratko objašnjenje zašto se u gotovo svakoj školi programiranja započinje s tako trivijalnim primjerom budući da on sam za sebe zapravo ne radi ništa korisno. Ideja u pripremi tako jednostavnog primjera jest u tome da se programer što brže upozna s novim programskim jezikom, ali i njegovim razvojnim okruženjem, kako bi se nakon toga što brže moglo prijeći na složenije probleme. Za pisanje novog programa potrebno je u razvojnoj okolini Eclipse izabrati naredbu File > New > Project te u dijaloškom okviru prikazanom u nastavku odabrati odgovarajuću vrstu projekta. U ovom slučaju to je Android Project. Kao rezultat izvođenja prethodne operacije, pojavljuje se dijaloški okvir New Android Project gdje se od programera očekuje upisivanje nekoliko polaznih podataka o vlastitom projektu. Project Name predstavlja naziv projekta na kojem trenutno radimo. U ovom slučaju, to će biti HelloWorld. Osim naziva projekta, potrebno je izabrati mjesto na disku za spremanje njegovih sastavnih dijelova. To može biti podrazumijevana radna površina definirana prilikom prvog pokretanja radne okoline, neko točno određeno mjesto na disku, ili se u razvoj projekta može krenuti od već postojećeg projekta – recimo nekog od pratećih primjera Google Android projekata. Za sada na ovom mjestu možemo ostaviti podrazumijevane vrijednosti, dakle – uključene opcije Create New Project in Workspace te Use default location.
Projekt HelloWorld nakon stvaranja: Automatski je generiran čitav niz datoteka koje se mogu pregledati u razvojnoj okolini Eclipse. Projekt HelloWorld nakon stvaranja: Automatski je generiran čitav niz datoteka koje se mogu pregledati u razvojnoj okolini Eclipse. U slučaju da je na računalo instalirano više inačica razvojnih paketa Google Android SDK, potrebno je izabrati jedan od njih, nakog čega će se odgovarajuća oznaka inačice pojaviti u okviru Min SDK Version na dnu dijaloškog okvira. Da bi se moglo nastaviti s radom na projektu, potrebno je navesti još nekoliko podataka. U okvir Application Name treba upisati naziv aplikacije, što može biti bilo kakav niz znakova, dakle i onaj jednak nazivu projekta. U Package Name treba upisati naziv Java paketa. Ovaj naziv treba biti sastavljen od najmanje dva dijela međusobno odvojena točkom – na primjer helloWorld.java (prema uobičajenim konvencijama prvo slovo treba biti malo). U okvir Create Activity treba upisati naziv prve aktivnosti u Google Android projektu – na primjer helloWorld. Sada je moguće kliknuti na gumb Next te tako prijeći na sljedeći dijaloški okvir namijenjen za stvaranje odgovarajućega pomoćnog projekta za testiranje. Projekti za testiranje namijenjeni su za pojednostavljeno ponavljanje testiranja vrlo složenih Google Android projekta (kakav HelloWorld zasigurno nije), ali ćemo na ipak kreirati takav projekt kako bismo se upoznali i s tom mogućnošću razvojnog alata. Na ovom mjestu mogu se ostaviti sve predložene vrijednosti što za posljedicu ima stvaranje projekta HelloWorldTest. Nakon izvođenja svih prethodno nabrojenih operacija, u radnoj površini na disku stvara se čitava „hrpa“ datoteka, a sadržaj svake od njih može se vidjeti u odgovarajućem prozoru radne okoline. Za jednostavnije snalaženje najbolje je koristi hijerarhijski prikaz dijelova projekta u posebnom prozoru na lijevom dijelu razvojne okoline (Navigator).
Upravljanje virtualnim uređajima: Omogućuje testiranje projekta na različitim emulacijama hardverskih karakteristika.
Budući da je razvojna okolina automatski pripremila čitav niz datoteka, prva ideja koja nam svakako mora pasti na pamet isprobavanje je nastale situacije. Najjednostavniji način za to jest odabir naredbe Run As > Android Application iz padajućeg izbornika povezanog s projektom HelloWorld. Podrazumijeva se da se ista naredba može izvesti na bar još nekoliko načina kao u svim modernim razvojnim okolinama – na primjer odabirom istoimene naredbe iz glavnog izbornika ili odgovarajuće ikone na alatnoj traci prozora. Na taj detalj više se nećemo vraćati ni u ovom ni u budućim tekstovima, nego istraživanje alternativnih mogućnosti ostavljamo samim čitateljima. Budući da je cijeli Android sustav namijenjen razvoju aplikacija za prijenosne mobilne uređaje, razumljivo je da se aplikacija ne može izvesti „u zraku“, nego nam je za to potreban nekakav uređaj za njezino izvođenje – ako ništa drugo, onda bar u obliku softverske emulacije. Takav softverski „stroj“ naziva se Android Virtual Device ili skraćeno AWD. Ako nekakva konfiguracija emulatora već ne postoji od prije, treba je pripremiti prema konkretnim potrebama za testiranje vlastite aplikacije. Za upravljanje virtualnim uređajima koristi se dijaloški okvir Android SDK and AVD Manager, što uključuje operacije poput stvaranja uređaja, njegovog brisanja, ispravljanja te možda najvažnije, pokretanja uređaja. Ključni hardverski parametri koji se mogu definirati kod stvaranja novoga virtualnog stroja jesu količina raspoložive radne memorije te rezolucija zaslona. Nakon stvaranja novoga virtualnog uređaja, u njega je moguće učitati, a nakon toga i isprobati vlastitu aplikaciju. Budući da za sada naša aplikacija predstavlja samo goli kostur aplikacije te kao takva zapravo ne radi ništa pametno, ni u virtualnom uređaju nema se mnogo toga za vidjeti osim osnovne poruke korisniku programa. U slučaju da se tekst iz aplikacije ne prikaže automatski u virtualnom uređaju, kliknite na gumb Menu prikazan na prozoru virtualnog uređaja. Trenutno stanje programskoga koda ima oblik prikazan u nastavku, ali ne treba smetnuti s uma da to nije jedini dio aplikacije. Tako, na primjer, za pregled i izmjenu prikazane poruke treba otvoriti datoteku strings.xml, hijerarhijski smještenu u mapi res/values. package helloWorld.java;import android.app.Activity; import android.os.Bundle;public class helloWorld extends Activity { /** Called when the activity is first created. */ @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); } } Na sličan način, otvaranjem datoteke main.xls smještene u mapi res/layout, može se oblikovati grafičko sučelje aplikacije na način vrlo sličan izvođenju odgovarajućih postupaka u drugim modernim razvojnim okolinama – na primjer Microsoft Visual Studio. Kao osnovnu vježbu u korištenju razvojne okoline, probajte u vlastitu aplikaciju dodati jedan gumb te mu eventualno podesiti neka od svojstava za određivanje izgleda u prozoru Properties.
Virtualni uređaj u akciji: Stvarni izgled ovisi o parametrima definiranim prilikom njegovog stvaranja.
Vizualna priprema sučelja aplikacije: Izvodi se u posebnom prozoru radne okoline.
Spomenimo na ovom mjestu kako se čitava operacija prevođenja izvornoga koda, pokretanja virtualnog uređaja te učitavanja prevedenog programa u uređaj može opisati svakako, ali sigurno ne pojmom „brza operacija“, bez obzira na snagu računala. Ako ste već ranije probali slične kombinacije razvojnih alata i emulatora drugih proizvođača, onda sigurno niste iznenađeni prethodnom tvrdnjom, jer ste na to već jednostavno navikli. Dobra vijest je da je vrijeme učitavanja nove inačice aplikacije u već pokrenuti virtualni uređaj bitno kraće, što znači da je isprobavanje vlastite aplikacije nakon manjih promjena izvornoga koda ipak prilično bezbolan proces. Spomenimo na kraju današnjeg predstavljanja početnih koraka u razvoju Android aplikacija, jer se dovršena i testirana Android aplikacija može pripremiti za distribuciju u obliku datoteke s nastavkom .apk. Riječ je o komprimiranoj datoteci sastavljenoj od većeg broja datoteka koje sadrže sve potrebne informacije za izvođenje aplikacije na uređaju s ugrađenom podrškom za Google Android. Kad završite ovu školu i napišete prve kvalitetne aplikacije, prruža vam se mogućnost da ponešto i zaradite putem online trgovine Google Android aplikacija, koja svakodnevno dobiva sve veći broj naslova od programera širom svijeta.
3. Interakcija sa korisnikom Drugi nastavak nove škole programiranja u razvojnom alatu Google Android bio je namijenjen izradi „klasične aplikacije“ u svim školama programiranja – općepoznatog primjera HelloWorld. Cilj projekta bio je brzo upoznavanje dijelova razvojne okoline potrebnih za izradu vlastitih aplikacija, dok o samom programiranju nije bilo rečeno baš mnogo. U biti, u prošlom tekstu samo smo isprobali ono što je automatski pripremila razvojna okolina. Ovaj put idemo korak dalje pa počinjemo u početnu aplikaciju dodavati prve objekte, a nakon toga i programski kod za njihovu reakciju na događaje u okolini, to jest na operacije korisnika programa. Usput ćemo se malo pozabaviti i posebnom terminologijom koja se koristi tijekom rada na Google Android projektima. Prije nego počnemo „zaozbiljno“, dopustite da se osvrnemo na bitan tehnički detalj. Moderna razvojna okolina kao što je Eclipse ima čitav niz prozora za definiranje različitih dijelova projekta, pa se početniku nije baš uvijek lako snaći sa svim tim dijelovima, posebno ako je neki od bitnih prozora zatvoren ili premješten s podrazumijevanog mjesta slučajno ili namjerno. Kako bi olakšao praćenje teksta, autor se trudi da priložene slike uz tekst uvijek pokazuju bitne dijelove. Problem nastaje kad se zbog ovog ili onog razloga (najčešće nedostatka prostora u časopisu), neka od slika mora izostaviti, ili se smanji tako da je teško razaznati neke dijelove. Zato ćemo (bar u početku) stalno navoditi ne samo što treba napraviti da bi se dovršila neka operacija nego i kako se zapravo stiže do tog mjesta. Navedimo prvo što želimo postići u današnjem i sljedećem nastavku. U osnovni projekt, HelloWorld, iz prošlog nastavka želimo dodati tri nova objekta – jedan okvir za prikaz i unos teksta od strane korisnika te dva dodatna gumba za upravljanje tim okvirom. Odmah pri pokretanju programa okvir za tekst se programski puni početnom vrijednošću, a pritisak mišem na bilo koji od dodatna dva gumba izaziva zamjenu početnog sadržaja drugačijim tekstom. Dakle, ništa spektakularno u smislu izvođenja programa, ali i tako jednostavan primjer demonstrira različite načine korištenja Google Android sustava u razvoju aplikacija za mobilne uređaje.
Rad na proširenju početnog HelloWorld projekta započinjemo otvaranjem datoteke main.xml u prozoru radne okoline, pod nazivom Android Layout Editor, jer je on namijenjen grafičkom uređivanju izgleda vlastite aplikacije. Naravno, budući da je u osnovi riječ o običnoj .xml datoteci, možemo je otvoriti i u nekom od tekstualno orijentiranih prozora, ali se to baš ne preporučuje početniku. Na ovom mjestu postoji velik stupanj analogije sa stvaranjem HTML dokumenata (što je vjerojatno poznato bar dijelu čitatelja). HTML dokument možemo stvoriti izravnim upisivanjem sastavnih dijelova u tekstualnom obliku (teži način), ili njihovim „crtanjem“ u odgovarajućem grafički orijentiranom alatu (lakši način). Za sada ćemo i u razvojnoj okolini Eclipse izabrati lakši način izrade korisničkog sučelja, a kad postanete iskusniji, možete koristiti oba načina. Spomenimo na ovom mjestu namjenu prozora Outline, koji zapravo predstavlja „nešto između“. U njemu je vidljiv samo popis osnovnih dijelova od kojih se sastoji korisničko sučelje aplikacije, kao i njihov međusobni odnos, ali ne i drugi detalji za određivanje izgleda. Korisničko sučelje aplikacije iz prošlog nastavka bilo je sastavljeno od svega dva dijela: LinearLayout i TextView. Prvi dio pripada grupi objekata namijenjenih određivanju međusobnog rasporeda osnovnih objekata koji čine korisničko sučelje (u terminologiji Google Androida to su layouts objekti). U današnjem nastavku nećemo se detaljnije baviti ovim dijelom oblikovanja korisničkog sučelja, nego to ostavljano za buduće nastavke serijala. Za sada spomenimo samo da je tijekom inicijalne pripreme projekta uporabljen prilično jednostavan raspored objekta pod prije spomenutim nazivom LinearLayout, a mi ćemo ga zasad koristiti bez ikakvih izmjena. U projekt HelloWorld automatski je dodan još jedan objekt namijenjen osnovnoj interakciji s korisnikom programa, što se zapravo svodilo na običan prikaz pozdravne poruke. U terminologiji Google Androida, takvi objekti s vlastitim vizualnim izgledom, namijenjeni izgradnji različitih dijelova korisničkog sučelja za interakciju s korisnikom aplikacije – nazivaju se widgets.
Već smo spomenuli da ćemo u korisničko sučelje dodati još tri dijela pa sad prelazimo na izvođenje odgovarajućih operacija. Iz prozora Views treba redom povući tri objekta na dio koji prikazuje grafičku reprezentaciju aplikacije (objekt LinearLayout). Jednom to treba napraviti s objektom tipa EditText, a dva puta s objektom tipa Button. O samom mjestu „ispuštanja“ objekta ne treba voditi previše računa, jer se pozicioniranje nacrtanih objekata ionako izvodi automatski zbog korištenja vrlo jednostavnog načina raspoređivanja objekata. Primijetimo na ovom mjestu da je razvojna okolina nacrtanim objektima automatski dodijelila nazive (EditText01, Button01 i Button02), baš kao i dio drugih vrijednosti svojstava. Ako ste već ranije koristili neku inačicu Microsoftove razvojne okoline, bit će vam potpuno jasno što se je dogodilo u prethodnom koraku. Isto tako, prepoznat ćete način za pregled i izmjenu podrazumijevanih vrijednosti svojstava aktivnog objekta. Za to se koristi prozor Properties, a u njemu treba jednostavno pronaći svojstvo čiji sadržaj namjeravamo izmijeniti te upisati (ili izabrati što ovisi o vrsti svojstva) novu vrijednost. Na primjer, ako želimo boju cjelokupne pozadine izmijeniti s crne na bijelu, kao aktivan objekt treba označiti LinearLayout, a kao vrijednost svojstva Background upisati vrijednost #FFFFFF. Na sličan način možemo gumbima Button01 i Button02 izmijeniti početni tekst na vrijednost Prihvati odnosno Odbaci, tako da za svaki gumb izvedemo korekciju vrijednosti svojstva Text. Objektu EditText01 također izmijenimo vrijednost svojstva Layout width na unaprijed definiranu vrijednost fill_parent, kako bi se objekt proširio na punu širinu. Za vježbu, možete promijeniti početnu vrijednost prikazanog teksta na objektu EditText01, iako ćemo to kasnije napraviti programski, kako bismo demonstrirali izmjenu vrijednosti svojstava u programskom jeziku.
Nestrpljivi čitatelji mogu probati sami otkrivati čemu služe druga dostupna svojstva tako da im izmijene početnu vrijednosti, a mi ćemo u sljedećim nastavcima serijala objašnjavati neka od njih kad nam zatrebaju. Objasnimo na ovom mjestu nešto zaobilazniji način za izmjenu vrijednosti svojstava. Vrijednost #FFFFFF na prvi, drugi pa čak i treći pogled početniku ne odaje da je riječ o bijeloj boji, a priznat ćete da ni iskusnijima nije baš lako pamtiti slične vrijednosti, ako ih ne koriste svakodnevno. Postoji li način da se takve vrijednosti koriste na „humaniji“ način? Srećom, da, a odgovarajući postupak opisujemo u nastavku teksta. U hijerarhijskom pregledu dijelova projekta (prozor Navigator) treba pronaći i otvoriti datoteku res \ values \ strings.xml. U ovoj datoteci nalaze se definicije resursa uporabljenih na različitim mjestima u programu. Na ovo mjesto treba jednostavno dodati novi resurs pod nazivom BijelaBoja. Za to se koristi klik na gumb Add.., nakon čega se otvara dijaloški okvir za odabir kategorije resursa. U njemu sasvim logično treba izabrati kategoriju Color, iako se potpuno sličan postupak primjenjuje za druge vrste resursa. Preostaje još samo da se kao naziv resursa (Name) upiše vrijednost BijelaBoja, a kao njegova vrijednost (Value) #FFFFFF. Naravno, nemojte zaboraviti ni na spremanje nove vrijednosti resursa pomoću ikone diskete na alatnoj traci razvojne okoline. Ako sada zatvorimo datoteku strings.xml, vraćamo se ponovno na grafičku reprezentaciju korisničkog sučelja. Ponovno kao aktivni objekt izaberimo LinearLayout te pronađimo svojstvo Background. Nakon klika na gumb s tri točke na samom desnom kraju reda, otvara se dijaloški okvir Reference Chooser. U njemu možemo pronaći vrijednost BijelaBoja u okviru kategorije Color te je izabrati kao novu vrijednost svojstva, potvrdom na gumb OK. Kao nova vrijednost svojstva sada će biti prikazana vrijednost @color/BijelaBoja, što i dalje predstavlja bijelu boju, ali sada napisanu na mnogo čitljiviji način od upisa heksadecimalnoga koda iste boje. Na sličan način možemo definirati druge vrijednosti koje namjeravamo uporabiti u različitim dijelovima programa. Za kraj današnjeg nastavka, otvorimo ponovno datoteku main.xml, ali sada u običnome tekstualnom editoru. Dobit ćemo nešto poput:
Sve ono što smo ranije dobili grafičkim oblikovanjem sučelja u nekoliko prozora razvojne okoline, ovdje je prikazano u običnom XML formatu zapisa. Iskusniji programeri mogu na ovom mjestu izravno izvoditi promjene, pa čak i dodavanje novih objekata na sučelje. Na primjer, probajte jednostavno umnožiti dio teksta namijenjen definiranju gumba Button02 pa ćete dobiti još jedan identičan gumb na korisničkom sučelju.
Primijetimo na kraju današnjeg nastavka da u XML opisu oba gumba postoji veza prema programskom kodu za obradu događaja onClick, jer je autor teksta to već pripremio u primjeru, ali zbog zadane veličine svakog pojedinog nastavka serijala, o tome će nešto više riječi biti u sljedećem broju.
4. Uvod u pisanje programskog koda U prošlom, trećem nastavku škole Google Android programiranja, u početnu inačicu aplikacije HelloWorld dodali smo nekoliko osnovnih grafičkih objekata, te usput objasnili više bitnih dijelova razvojne okoline Eclipse, povezanih s postavljanjem i pregledom grafičkih objekata korištenih u aplikaciji, odnosno pripremom i izmjenom njihovih svojstava. Međutim, tako dugo dok nacrtanim objektima ne dodamo nekakav programski kod, oni u aplikaciji služe manje‐više samo kao ukras, pa kao takvi ne rade ništa pametno. Tek kada se objektima pridruže odgovarajuće funkcije za reakciju objekta na „podražaj“ iz okoline (recimo pritisak na objekt od strane korisnika aplikacije na zaslonu uređaja), počinje se doista nešto događati. Vratimo se na trenutak ponovno na tekstualni prikaz dijela datoteke main.xml, zadužene za definiranje izgleda objekata u aplikaciji, ali istovremeno i za povezivanje nacrtanih objekata s dijelovima programskoga koda. Usredotočimo se u nastavku na sljedeće dijelove datoteke: … …
Povezivanje objekata s programskim kodom: Izvedivo je izravnim uređivanjem tekstualnog sadržaja datoteke Main.xml. Dijelovi označeni istaknutim pismom zaduženi su za povezivanje oba „nacrtana“ gumba u sučelju s odgovarajućom funkcijom u programskom kodu – u ovom slučaju ona je zadužena za obradu događaja izazvanog pritiskom korisnika na kontrolu. Da odmah razjasnimo jednu vrlo bitnu stvar (kako se čitatelji ne bi našli u svojevrsnoj konfuziji pri praćenju teksta), iako smo je već spomenuli na kraju prethodnog nastavka. Ako se pozorno pratili tekst iz prošlog broja te pokušali ponoviti sve opisane operacije, onda u vašem projektu trenutno nema navedenih dijelova. U projektu autora teksta ti dijelovi postoje, jer je primjer prvo napravljen do kraja, a tek onda je započeto pisanje teksta. Odatle dolazi do istaknute razlike između projekata, ali ćemo odmah poduzeti sve potrebne operacije da ih uklonimo. Na koji način u vlastite projekte možete dodati dio koji nedostaje? Jedan od načina izravni je upis prije označenoga teksta u prozoru zaduženom za tekstualni prikaz sadržaja datoteke main.xml. Drugi način korištenje je prozora Properties, nakon što željeni objekt postane aktivan objekt (vidi priloženu sliku uz tekst). U našem primjeru oba objekta povezana su s istim dijelom programskog koda, jer se u njemu na jedinstven način prvo provjerava objekt na koji je korisnik programa napravio pritisak. Moguće je napraviti i drugačije rješenje. Svaki gumb može biti povezan s posebnom funkcijom za obradu događaja. Na autoru programa je odlučiti što je najbolje izabrati u određenoj situaciji. Pripadajući programski kod primjera u ovom trenutku ima sljedeći oblik (datoteka HelloWorld.java): package helloWorld.java; import android.app.Activity;
import android.os.Bundle; import android.view.View; import android.widget.EditText; import android.os.Bundle; public class helloWorld extends Activity { private EditText text; /** Called when the activity is first created. */ @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); text = (EditText) findViewById(R.id.EditText01); text.setText(“No button pressed”); } // Will be connected with the buttons via XML public void myClickHandler(View view) { switch (view.getId()) { case R.id.Button01: text.setText(“Button 1 was clicked”); break; case R.id.Button02: text.setText(“Button 2 was clicked”); break; } } }
U prethodnom primjeru mogu se uočiti tri glavna dijela. Prvo je naveden čitav niz import naredaba kako bi se u vlastiti program uključili svi potrebni dijelovi za izvođenje aplikacije. Pomoću dijela: public void onCreate(Bundle savedInstanceState) { započinje drugi dio, odnosno izvođenje glavnog dijela programa. U njemu se, osim inicijalizacije same aplikacije, postavlja početna vrijednost tekstualnog sadržaja za trenutno jedini objekt u aplikaciji zadužen za prikaz odnosno unos teksta (EditText01). Za to su zadužene naredbe za njegovo „pronalaženje“ među postojećim objektima, a nakon toga za postavljanje početne vrijednosti. setContentView(R.layout.main); text = (EditText) findViewById(R.id.EditText01); text.setText(“No button pressed”); Kao što smo to već spomenuli, u ovom primjeru oba gumba u aplikaciji povezana su na zajednički dio programskoga koda za obradu događaja.
Alternativni način povezivanja: Korištenje prozora Properties u razvojnoj okolini Eclipse. Pomoću naredbe switch provjerava se o kojem je gumbu doista riječ, a onda se izvodi jedan od dva moguća nastavka. Svaki od njih izaziva prikaz drugačije poruke u prije spomenutomu tekstualnom okviru. Ako je sve napravljeno precizno, prema uputama iz ovog i prethodnog nastavka serijala, tijekom izvođenja programa trebali biste dobiti identično ponašanje programa kao na slikama uz tekst.
Pokupajmo sada u svrhu svojevrsne vježbe opisati sve potrebne izmjene kako bi u programskom kodu primjera svaki gumb imao vlastitu proceduru za obradu događaja. U praksi je to zapravo češće rješenje zbog velike razlike između namjene pojedinih gumba u aplikaciji. Postojeći programski kod primjera helloWorld.java u tom slučaju treba izmijeniti u sljedeći oblik. package helloWorld.java; import android.app.Activity; import android.os.Bundle; import android.view.View; import android.widget.EditText; import android.os.Bundle; public class helloWorld extends Activity { private EditText text; /** Called when the activity is first created. */ @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); text = (EditText) findViewById(R.id.EditText01); text.setText(“No button pressed”); } // first Button public void myClickButton1(View view) { text.setText(“Button 1 was clicked”); } // second Button public void myClickButton2(View view) { text.setText(“Button 2 was clicked”);
} }
Početni izgled prozora: Nakon pokretanja programa pojavljuje se početna poruka. Budući da zajednička funkcija za obradu događaja nakon pritiska na gumb više ne postoji, nego je zamijenjena s dvije pojedinačne funkcije, treba korigirati veze između oba gumba i pripadajućega programskoga koda. To se ponovno može napraviti izmjenom svojstva On click u prozoru Properties te upisivanjem vrijednosti myClickButton1, odnosno myClickButton2. Klikom na gumb na krajnjoj desnoj strani toga reda može se prikazati i dijaloški okvir za odabir postojećih dijelova programskoga koda. Alternativni način za izvođenje iste operacije (nešto brži, ali zahtijeva veću preciznost u pisanju) izravna je izmjena tekstualnog sadržaja datoteke main.xml. U konačnici, bez obzira na uporabljeni način izmjene vrijednosti, u toj datoteci treba biti sljedeći sadržaj. …
… Ovime je dovršen početni niz tekstova o razvoju aplikacija pomoću Google Android platforme. Ako ste pozorno pratili sve što je do sada napisano o ovoj temi, sada biste na vlastitom računalu trebali imati pravilno instaliran razvojni sustav, a ujedno biste ga trebali poznavati do razine korištenja koja omogućuje praćenje i upis primjera iz sljedećih nastavaka serijala. Kao i obično u školama programiranja, praćenje tekstova olakšat ćemo izdavanjem pratećih primjera na digitalnomu mediju uz časopis. Što ćemo raditi u budućim nastavcima? Zbog relativne ograničenosti prostora za ovaj serijal u časopisu, škola programiranja u razvojnom alatu Google
Izgled prozora nakon klika na prvi gumb: Početna poruka zamjenjuje se novom porukom. Android dalje će izgledati nešto drugačije nego što je to bio slučaj s prethodnim sličnim materijalima istog autora. To znači da nećemo obrađivati segment po segment programskoga jezika ni pratećih biblioteka funkcija, a onda izmišljati odgovarajući primjer za njihovu demonstraciju, nego ćemo raditi upravo obrnutim redoslijedom. Prvo ćemo napraviti jedan ili više složenijih primjera namijenjenih demonstraciji različitih mogućnosti Google Android platforme, a onda objasniti što rade ključni dijelovi primjera. Kao što smo istaknuli na samom početku serijala, za praćenje tako koncipiranih nastavaka očekuje se određeno predznanje u smislu poznavanja osnovnih pojmova uobičajenih u programerskom žargonu, poput varijable, petlje ili procedure. Drugim riječima, to bi trebalo značiti da već posjedujete osnovno praktično znanje programiranja u nekom drugom razvojnom alatu. U međuvremenu, dok čekate sljedeći bitno kompliciraniji nastavak serijala, možete sami pokušati dodati u projekt nekoliko novih gumba ili drugačijih vrsta kontrola, a onda ih povezati s osnovnim događajem na korisničkom sučelju (On click).
5. Korištenje rasporeda kontrola u složenim aplikacijama Nakon što smo prošli put „dotjerali do kraja“ s nešto složenijim Android projektom u kojem je bilo i malo više programskog koda, došao je trenutak da se detaljnije pozabavimo najvažnijim dijelovima razvojnog alata, kako bi u slijedećim nastavcima mogli izrađivati ozbiljnije aplikacije. Jedna od tipičnih karakteristika svake složenije aplikacije, bez obzira na softversku platformu na kojoj se izvodi, je postojanje većeg broja prozora, formi ili zaslona (već prema terminologiji uobičajenoj za tu razvojnu platformu) u okviru iste aplikacije. Ni Android aplikacije po tom pitanju nisu nikakav izuzetak. U dosadašnja dva jednostavna primjera aplikacija iz prethodnih nastavaka serijala koristili smo isti pogled (odnosno istu vrstu rasporeda osnovnih objekata) pod nazivom LinearLayout. U tim primjerima zapravo se nismo previše obazirali na karakteristike korištenog rasporeda kontrola, nego smo jednostavno po njemu postavili ostale objekte korištene u aplikaciji (dva gumba i jedan okvir za unos teksta). Glavna tema današnjeg teksta posvećena je upravo različitim vrstama rasporeda osnovnih kontrola dostupnim u okviru Android platforme, što uključuje opisivanje njihovih mogućnosti i načina korištenja. U okviru Google Android platforme dostupne su slijedeće vrste rasporeda osnovnih objekata: 1. 2. 3. 4. 5. 6.
LinearLayout AbsoluteLayout TableLayout RelativeLayout FrameLayout ScrollView
Početni raspored osnovnih kontrola: Koristi se podrazumijevani raspored osnovnih kontrola LinearLayout. Prije nego što malo detaljnije objasnimo svaki od rasporeda, posvetimo riječ, dvije izvornoj terminologiji te hrvatskim pojmovima korištenim u tekstu. U originalnoj terminologiji osnovni objekti (npr. gumb, okvir za tekst i slično) nazivaju se Widget, a kad su vidljivi na zaslonu View. Pojmom ViewGroup (u osnovi također posebnoj vrsti pogleda) označava se skupina osnovnih „Viewa“ razmještena po zaslonu u određenom rasporedu – to je ovih 6 rasporeda spomenutih u prethodnom nabrajanju. Sad kad smo nabrojili temeljne engleske pojmove navedimo i to koje ćemo prijevode koristi u nastavku teksta da ne stvaramo nepotrebnu zabunu. Umjesto pojmova Widget i View koristit ćemo riječi objekt ili kontrola, dok će ViewGroup biti zamijenjen s pogled ili raspored kontrola. To možda nije najbolje moguće rješenje prijevoda, ali s druge strane predstavlja vrlo čestu terminologiju korištenu u opisu drugih razvojnih alata. Ako ste već koristili neki od njih, bez problema ćete pratiti rečenice u tekstu kojeg upravo čitate. Vratimo se sada na glavnu temu današnjeg teksta – korištenje različitih rasporeda osnovnih kontrola u vlastitim aplikacijama. Obavimo to istim redom kao u ranijem nabrajanju. LinearLayout predstavlja osnovni raspored kontrola gdje su sve osnovne kontrole raspoređene u samo jednom redu ili samo jednom stupcu. Tijekom rada na osnovna dva projekta u prethodnim nastavcima, nove kontrole su se uvijek pojavljivale jedna ispod druge, jer smo koristili upravo taj osnovni raspored kontrola automatski predložen od strane razvojne okoline tijekom stvaranja projekta. Iako za složenije aplikacije ovakav raspored osnovnih kontrola nije uvijek i najpogodnije rješenje, kod početnih koraka u novom razvojnom alatu zapravo nema nekih prevelikih zamjerki na njegovo korištenje. Kod drugog od spomenutih rasporeda kontrola AbsoluteLayout programer nije ograničen na neki od podrazumijevanih oblika „redanja“ osnovnih kontrola po pozadini, nego ima potpunu slobodu u njihovom postavljanju na dostupnom području. O samim svojstvima potrebnim za pozicioniranje svake pojedine kontrole na ovakvoj vrsti pogleda odnosno rasporeda, bit će više riječi slijedeći put. Raspored kontrola pod nazivom TableLayout, kao što to sam naziv govori, koristi se kod razvrstavanja osnovnih kontrola u više redova ili stupaca tablice, odnosno u čelije tablice. Na taj način mogu se dobiti „lijepi“ pravilni rasporedi osnovnih kontrola na pogledu, što se vrlo često koristi kod različitih vrsta unosa podataka u aplikacijama. U RelativeLayout rasporedu kontrole se mogu postaviti na različita mjesta na dostupnom prostoru za njihovo prikazivanje, ali točno mjesto svake kontrole nije određeno njezinim apsolutnim koordinatama kao kod rasporeda pod nazivom AbsoluteLayout, nego je pozicija osnovne kontrole definirana relativnim koordinatama prema drugoj osnovnoj kontroli. FrameLayout se u aplikacijama koristi za rezerviranje mjesta za naknadno postavljanje drugih kontrola tako da se one uvijek „sidre“ prema gornjem lijevom uglu FrameLayout rasporeda kontrola. Sve će biti jasnije kad se to prikaže slikom u nekoj od budućih aplikacija. Zadnja vrsta rasporeda osnovnih kontrola pod nazivom ScrollView koristi se u slučajevima kad na fizičkim dimenzijama zaslona jednostavno nije moguće prikazati sve potrebne osnovne kontrole na smislen i pregledan način (bez međusobnog preklapanja i jasnog razdvajanja). Pogled ScrollView zapravo predstavlja posebnu vrstu rasporeda FrameLayout na koju se u praksi obično postavlja dodatna vrsta osnovnog rasporeda kontrola (RelativeLayout).
U okviru jedne složene aplikacije može se koristiti veći broj istih ili različitih vrsta rasporeda kontrola, između kojih se prebacivanje, to jest aktiviranje nekog drugog rasporeda, izvodi pomoću programskog koda. Pogledajmo sada kako korištenja različitih rasporeda izgleda na nekoliko primjera. Osnovni raspored kontrola iz dovršenog primjera u prethodnom nastavku, koji je koristio podrazumijevani raspored LinearLayout imao je slijedeći XML oblika zapisa.
Raspored kontrola AbsoluteLayout: Sve kontrole se preklapaju jer još nisu upisane njihove apsolutne koordinate. Ako u prethodnom XML kodu izmijenimo samo naziv rasporeda LinearLayout u AbsoluteLayout, sve kontrole „skupit“ će se u gornjem lijevom uglu prikaza, jer bi u ovakvom rasporedu trebalo obavezno navesti apsolutne vrijednosti pozicija kontrola. Budući da to još uvijek nismo napravili, uzete su podrazumijevene vrijednosti 0, što je izazvalo spomenuto skupljanje kontrola. Navođenjem apsolutnih vrijednosti za poziciju i veličinu kontrola dolazi do njihovog željenog formatiranja, kao što to pokazuje prateća slika uz tekst.
Raspored kontrola AbsoluteLayout: Za svaku kontrolu su navedene apsolutne vrijednosti za određivanje izgleda. Zamjenom apsolutnog rasporeda kontrola relativnim u okviru XML definicije više nije potrebno navoditi apsolutne vrijednosti pozicija kontrola, nego samo njihovu relativnu poziciju u odnosu na neku drugu kontrolu. Apsolutne vrijednosti zadužene za definiranje veličine kontrole mogu se koristiti i dalje na isti način. Na temelju slijedećeg XML sadržaja, pomoću relativnog rasporeda kontrola oponašan je početni raspored kontrola LinearLayout. U prethodna tri primjera korišteno je nekoliko dodatnih elemenata za definiranje rasporeda osnovnih kontrola u okviru osvnovne XML datoteke za
Raspored kontrola RelativeLayout: U ovom slučaju je oponašan osnovni raspored LinearLayout. definiranje izgleda zaslona. Nešto više riječi o njihovoj namjeni možete pročitati u slijedećem broju.
6. Korištenje osnovnih Android kontrola Nakon što smo raspravili što su to zapravo rasporedi osnovnih kontrola, u današnjem nastavku uvoda u Android programiranje možemo prijeći na drugi bitan preduvjet izrade korisničkog sučelja, a to je upoznavanje osnovnih kontrola namijenjenih za postavljenje na takve rasporede. No, prije toga evo jednog primjera programskog koda (za kojeg nije bilo mjesta u prošlom nastavku), gdje se korisničko sučelje u potpunosti stvara programskim kodom. Drugim riječima, ako je programeru iz nekog razloga tako zgodnije, ne mora prvo „crtati“ korisničko sučelje u odgovarajućem prozoru razvojne okoline, a onda dodavati programski kod da „oživi“ nacrtane kontrole, nego sve to može napraviti u jednom prolazu isključivo programskim kodom. Ako ste već u prošlosti koristili Microsoft Visual Studio, onda će vam sve biti mnogo jasnije kad napišemo da je riječ o postupku analognom dinamičkom dodavanju kontrola na formu tijekom izvođenja programa. package Hello.Android; import android.app.Activity; import android.os.Bundle;
import android.view.ViewGroup.LayoutParams; import android.widget.LinearLayout; import android.widget.TextView; public class HelloActivity extends Activity { private LinearLayout prezimeime; private LinearLayout adresa; private LinearLayout podloga; /** Called when the activity is first created. */ @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); createPrezimeIme(); createAdresa(); createPodloga(); setContentView(podloga); } private void createPodloga() { podloga = new LinearLayout(this); podloga.setLayoutParams(new LayoutParams(LayoutParams.FILL_PARENT, LayoutParams.FILL_PARENT)); podloga.setOrientation(LinearLayout.VERTICAL); podloga.addView(prezimeime); podloga.addView(adresa);
} private void createPrezimeIme() { prezimeime = new LinearLayout(this); prezimeime.setLayoutParams(new LayoutParams(LayoutParams.FILL_PARENT, LayoutParams.WRAP_CONTENT)); prezimeime.setOrientation(LinearLayout.HORIZONTAL); TextView prezimeLbl = new TextView(this); prezimeLbl.setText(“Prezime ime: “); TextView prezime2Lbl = new TextView(this); prezime2Lbl.setText(“Android Vid”); prezimeime.addView(prezimeLbl); prezimeime.addView(prezime2Lbl); } private void createAdresa() { adresa = new LinearLayout(this); adresa.setLayoutParams(new LayoutParams(LayoutParams.FILL_PARENT, LayoutParams.WRAP_CONTENT)); adresa.setOrientation(LinearLayout.VERTICAL); TextView adresaLbl = new TextView(this); adresaLbl.setText(“Adresa:”); TextView adresa2Lbl = new TextView(this); adresa2Lbl.setText(“Redacija VIDI”); adresa.addView(adresaLbl); adresa.addView(adresa2Lbl);
} }
Stvaranje rasporeda kontrola i samih kontrola pomoću programskog koda: Ne treba uvijek prvo nacrtati kontrole u razvojnoj okolini. Prethodni programski primjer tijekom svojeg izvođenja stvara osnovni raspored kontrola pod nazivom podloga, a onda na njega dodaje tekstualne kontrole za prikaz imena i adrese. Sličan postupak se može primijeniti za sve vrste kontrola. Ako ne volite prekucavati primjere, možete ga pronaći na pratećem digitalnom mediju uz časopis. Vratimo se sada glavnom dijelu teksta – kontrolama namijenjenim postavljanju na neki od osnovnih rasporeda kontrola te njihovim najbitnijim svojstvima. Ako ste već koristili neki od modernijih razvojnih alata, ponovo ćete pronaći dosta sličnosti, a ako niste, onda svakako pogledajte tekst u nastavku te sami pokušajte napraviti nekoliko vlastitih primjera s takvim kontrolama. Kontrole ćemo u nastavku prikazati prema učestalosti u aplikacijama – dakle prvo one koje se najčešće koriste.
TextView Kontrola tipa TextView namijenjena je prikazu različitih vrsta tekstova na zaslonu, ali bez mogućnosti njihove izmjene odnosno uređivanja. Zato se ova vrsta kontrole u vlastitim aplikacijama najčešće koristi za prikaz informacija korisniku poput dodatnih opisa uz glavne kontrole koje omogućavaju uređivanje teksta. Međutim, ako dio prikazanog teksta predstavlja web adresa, onda se kontrola može upotrijebiti znatno kreativnije, tako da klik mišem na web adresu otvara preglednik te prikazuje njezin sadržaj (vidi primjer slike uz tekst).
Da bi demonstrirali takvo ponašanje kontrole TextView u prethodnom programskom primjeru treba napraviti dvije izmjene. Prvo, treba u aplikaciju uključiti posebnu klasu za pronalaženje veze prema veb adresi u tekstualnom nizu znakova (klasa Linkify): import android.widget.LinearLayout; import android.widget.TextView; import android.text.util.Linkify; a onda dodati novu kontrolu nazvanu txtWeb čiji tekstualni sadržaj uključuje web adresu: private void createPodloga() { podloga = new LinearLayout(this); podloga.setLayoutParams(new LayoutParams(LayoutParams.FILL_PARENT, LayoutParams.FILL_PARENT)); podloga.setOrientation(LinearLayout.VERTICAL); podloga.addView(prezimeime); podloga.addView(adresa); TextView txtWeb = new TextView(this); txtWeb.setText(“Dodatne informacije o Android programiranju na http://www.vidilab.com/”); Linkify.addLinks(txtWeb, Linkify.ALL); podloga.addView(txtWeb); } Nakon pokretanja programa, kao što to demonstrira prateća slika uz tekst, u sadržaju kontrole pojavljuje se posebno istaknuta web adresa, a klik na adresu otvara njezin sadržaj u podrazumijevanom pregledniku.
EditText Ako je korisniku potrebno omogućiti da u programu upiše odnosno da uredi postojeći tekstualni sadržaj, onda umjesto kontrole tipa TextView treba
Korištenje kontrole TextView: Omogućava i otvaranje sadržaja zadane web adrese. koristiti kontrolu tipa EditText. Treba istaknuti kako ni ova vrsta kontrole nije zamišljena za upis velikih tekstova, nego prije svega kraćih podataka kakvi se obično zapisuju u pojedine stupce baze podataka. Kontrola EditText posjeduje brojna dodatna svojstva čijom promjenom vrijednosti se može bitno izmijeniti ponašanje kontrole, prije svega način prikaza teksta. Na primjer: Auto text – automatski ispravlja moguće pogreške tijekom upisa teksta Capitalize – pretvara upisana slova u velika slova Numeric – postavlja brojčani unos podataka Password – postavlja upis lozinke (ne vide se znakovi kod upisa) Phone number ‐ postavlja unos telefonskog broja Single line ‐ definira unos teksta u jednom redu Slijedeći primjer pokazuje dinamičko dodavanje tekstualne kontrole na osnovni raspored kontrola uz korištenje dvije dopunske metode za prikaz dodatnih informacija uz kontrolu. private void createPodloga() { podloga = new LinearLayout(this); podloga.setLayoutParams(new LayoutParams(LayoutParams.FILL_PARENT, LayoutParams.FILL_PARENT));
podloga.setOrientation(LinearLayout.VERTICAL); podloga.addView(prezimeime); podloga.addView(adresa); /* dodatak 1 – primjer korištenja kontrole TextView */ TextView txtWeb = new TextView(this); txtWeb.setText(“Dodatne informacije o Android programiranju na http://www.vidilab.com/”); Linkify.addLinks(txtWeb, Linkify.ALL); podloga.addView(txtWeb); /* dodatak 2 – primjer korištenja kontrole EditText */ EditText txtKorisnik = new EditText(this); txtKorisnik.setText (“Upišite korisničko ime”); txtKorisnik.setHint(“Pazite na upis malih i velikih slova”); txtKorisnik.setError(“Pazite na veličinu slova”); podloga.addView(txtKorisnik); }
Rezultat klika na web adresu u kontroli TextView: Prikaz sadržaja zadane adrese u pregledniku. Posebnu vrstu kontrola za upis teksta predstavljaju kontrole AutoCompleteTextView te MultiAutoCompleteTextView. Njihova najvažnija značajka je da tijekom upisa/ispravljanja teksta omogućavaju automatsko dovršavanje upisanog teksta. Evo i primjera odgovarajućeg programskog koda nadopisanog na kraj postojećeg programskog koda u funkciji createPodloga. private void createPodloga() { podloga = new LinearLayout(this); podloga.setLayoutParams(new LayoutParams(LayoutParams.FILL_PARENT, LayoutParams.FILL_PARENT)); podloga.setOrientation(LinearLayout.VERTICAL); podloga.addView(prezimeime); podloga.addView(adresa); /* dodatak 1 – primjer korištenja kontrole TextView */ TextView txtWeb = new TextView(this); txtWeb.setText(“Dodatne informacije o Android programiranju na http://www.vidilab.com/”); Linkify.addLinks(txtWeb, Linkify.ALL); podloga.addView(txtWeb); /* dodatak 2 – primjer korištenja kontrole EditText */
Primjer korištenja kontrole EditText: Kontrola se koristi za upis i izmjenu teksta. EditText txtKorisnik = new EditText(this); txtKorisnik.setText (“Upišite korisničko ime”); txtKorisnik.setHint(“Pazite na upis malih i velikih slova”); txtKorisnik.setError(“Pazite na veličinu slova”); podloga.addView(txtKorisnik); /* dodatak 3 – primjer korištenja kontrole AutoCompleteTextView */ AutoCompleteTextView actv = new AutoCompleteTextView(this); ArrayAdapter aa = new ArrayAdapter(this, android.R.layout.simple_dropdown_item_1line, new String[] {“English”, “Hebrew”, “Hindi”, “Spanish”, “German”, “Greek” }); actv.setAdapter(aa); podloga.addView(actv); }
Nakon upisa početnih slova (npr. en) automatski se predlaže podudarajuća potpuna tekstualna vrijednost, pa se ona nakon toga može jednostavno izabrati umjesto da se upisuje u cijelosti.
Buttons Android platforma omogućava korištenje tri različita tipa gumbi – osnovni gumb (Button Control), gumb sa slikom (ImageButton Control) te gumb s mogućnošću prikaza dva različita stanja gumba (ToggleButton Control). Osnovni tip gumba već smo koristili u primjerima iz prethodnih nastavaka serijala, a detaljne mogućnosti korištenja sva tri tipa gumbi predstavit ćemo u slijedećem nastavku serijala zajedno s ostatkom osnovnih kontrola.
7. Android programiranje
S predstavljanjem osnovnih Android kontrola prošli put smo zastali na dobro poznatim gumbima (Buttons). Kao i u drugim modernim operativnim sustavima ovaj tip kontrole koristi se u aplikacijama za izvođenje različitih operacija, a (ponovo kao i u drugim operativnim sustavima) može imati nekoliko pojavnih oblika. Osnovni oblik gumba (Button) na sebi sadrži samo običan tekst koji označava kakvu će operaciju u okviru određene aplikacije izazvati pritisak na gumb. Ako zadnjih nekoliko desetljeća niste proveli izolirani u samici nekog zaostalog nedemokratskog režima bez ikakvog kontakta s modernim računalima, onda je prethodna rečenica sasvim dovoljna da shvatite o čemu je ovdje riječ. Budući da smo ovaj gumb već nekoliko puta koristili u primjerima iz prethodnih nastavaka serijala, kako u pogledu izmjene osnovnih svojstava, tako i u pogledu dodavanja programskog koda, nećemo se više ni baviti njime. Budući da se moderna korisnička sučelja sve više temelje na slici nego na riječi, razumljivo da je običan gumb doživio svojevrsnu vizualnu nadogradnju, postavši tako u Android terminologiji kontrola pod nazivom ImageButton. Namjena unaprijeđene kontrole je potpuno jednaka kao i u njezinom osnovnom obliku, jedino što takav gumb može izgledati bitno ljepše (što izravno ovisi o slici postavljenoj na njegovu površinu). Upravo je zamjena osnovnih vrsta gumbi slikovnim jedan od najvažnijih, ali ujedno i najjednostavnijih načina da vlastitu aplikaciju učinite atraktivnijom te u konačnici privlačnijom potencijalnim korisnicima. Slikovna verzija gumba povezuje se s odgovarajućom datotekom s grafičkim sadržajem pomoću svojstva src, što se može napraviti u za to namijenjenom prozoru razvojne okoline, izravno u XML datoteci, ili programskim kodom. U priloženoj segmentu XML datoteke prikazan je primjer korištenja drugog od nabrojenih načina, dok se za istu namjenu u programskom kodu treba koristiti metoda setImageResource(). Treća vrsta gumba pod nazivom ToggleButton omogućava prikaz više stanja iste pojave unutar aplikacije. Na primjer, jednim stanjem gumba može se pokazati da je uključen nekakav parametar odnosno izvođenje nekakve operacije, a drugim stanjem da je parametar isključen odnosno da je prekinuto izvođenje operacije. U praksi se takva vrsta gumbi najčešće koristi za prilagođavanje različitih dijelova aplikacije željama i potrebama korisnika aplikacije. Kao što to ponovo prikazuje priložena XML datoteka sa definicijama sve tri vrste opisanih gumbi, pomoću dva dodatna svojstva gumba android:textOn=”Pokrenuto” android:textOff=”Zaustavljeno”> moguće je definirati dva
različita tekstualna sadržaja za prikazivanje na samom gumbu ovisno o njegovom trenutnom stanju (uključeno / isključeno). Kako izgleda korisničko sučelje nastalo na temelju prethodne XML datoteke možete vidjeti na priloženoj slici uz današnji tekst. Zadnjoj od prije opisanih kontrola prilično slične su još dvije vrste kontrola. To su CheckBox i RadioButton. Riječ je o kontrolama koje su zapravo i poznatije korisnicima aplikacija, jer su osim na
Android platformi prisutne u praktično svim modernim grafičkim sučeljima današnjice. Obje od navedenih kontrola omogućavaju uključivanje/isključivanje različitih opcija, ali se međusobno razlikuju u situacijama kad u korisničkom sučelju aplikacije postoji više kontrola istog tipa. CheckBox kontrole su u pogledu međusobnog stanja neovisne jedne od druge, što znači da uključivanje ili isključivanje jedne od kontrola ne utječe na stanje druge kontrole. Osim promjene trenutnog stanja od strane krajnjeg korisnika aplikacije, vrijednosti se mogu postavljati programskim kodom korištenjem metode setChecked() dok se trenutno stanje može dobiti pomoću isChecked(). Trenutno stanje neke RadioButton kontrole ovisi o stanju drugih kontrola iste vrste, što drugim riječima znači da u jednom trenutku samo jedna od takvih kontrola može biti uključena, dok sve druge kontrole automatski poprimaju vrijednost isključeno. Zato se ova vrsta kontrola koristi za rad s vrijednosti koje se međusobno isključuju. Sa stanovišta programskog koda uključivanje/isključivanje stanja kontrole provodi se na sličan način kao i kod CheckBox kontrola. Spomenimo na ovom mjestu i to da se pojam međusobnog isključivanja RadioButton kontrola odnosi na kontrole u istom „spremniku“ kontrola. Ako u aplikaciji trebaju postojati dvije neovisne grupe takvih kontrola, onda treba pripremiti i dva spremnika (npr. rasporeda kontrola). Evo kratkog segmenta XML datoteke namijenjenog definiranju obiju vrsta kontrola. CheckBox kontrole: : Building User Interfaces and Using Controls
RadioButton kontrole:
Korištenje gumbi: Programeru su na raspolaganju tri različite vrste gumbi. U izmišljenoj aplikaciji za naručivanje u restoranu u prvom slučaju korisnik aplikacije može označiti različite dijelove obroka neovisno jedan o drugome, a u drugom slučaju za glavni obrok može izabrati samo jednu od vrsta glavnog jela (mesa). Nekoliko riječi o hardveru Dozvolite da na kraju današnjeg nastavka softverskog serijala napišemo par riječi o dosta zanimljivom hardverskom uređaju – Eken M001. Riječ je o 7 inčnom uređaju s ugrađenom Goolge Android platformom u verziji 1.6, te dobrim mogućnostima proširivanja i povezivanja s običnim računalom. U slučaju da pripadate grupi programera koja završno testiranje vlastitog softvera želi provesti na pravom hardveru, a ne samo njegovom simulatoru, teško da ćete proći jeftinije. Hardver nabrojen u slijedećoj tablici možete dobiti po cijeni manjoj od 100 dolara, a zanimljivo je da se uređaj može pronaći čak i po domaćim malim oglasnicima.
Eken M001: Vrlo jeftini hardver s implementacijom Google Android platforme. U posljednje vrijeme domaći operateri mobilnih usluga počeli su nuditi podosta naprednije uređaje od navedenog. Ako odaberete odgovarajući pretplatnički odnos možete proći čak i jeftinije, ali ne smijete zaboraviti da vas pretplatnički odnos veže na indirektno plaćanje uređaja na najmanje godinu ili dvije dana. S druge strane nabavkom M001, dobivate sasvim upotrebljivi uređaj za čitanje različitih materijala spremljenih izravno u njegovu memoriju ili pristupom preko Wi‐fi mreže, igranje, reprodukciju multimedijalnih sadržaja i još ponešto. Nije iPod, ali iz daljine nitko to neće ni primijetiti. Prema iskustvima autora teksta najvažniji nedostatak uređaja je prilično skromno trajanje baterija pa budite spremni da osim sa sobom stalno nosite i ispravljač za njegovo nadopunjavanje.
8. Android kontrole u akciji IV Vrlo važan dio gotovo svake aplikacije (osim onih krajnje trivijalnih, ili onih koje su potpuno optimizirane za neko specijalizirano područje) je upravljanje vremenom. Čak i različite igre, kao kategorija aplikacija kakve se vrlo često pišu za mobilne uređaje uključujući i Android platformu, često spremaju različite podatke o igraču ili statusu igre povezane s datumom i vremenom. Naravno, za prikaz ili izmjenu datuma i vremena programer uvijek može izmisliti svoje vlastite kontrole, ali nije loše kad je i osnovni razvojni sustav opremljen odgovarajućim kontrolama. To posebno vrijedi kod aplikacija s naglaskom na funkcionalnosti, a ne na vizualnoj raskoši. Android platforma opremljena je s dvije međusobno prilično različite vrste kontrola za tu namjenu. Prva grupa kontrola može samo prikazati podatke o vremenu, dok ih druga vrsta može prikazati, ali i dozvoliti izmjenu vrijednosti od strane krajnjeg korisnika aplikacije. U prvu grupu kontrola pripadaju kontrole AnalogClock i DigitalClock (sam naziv u potpunosti govori o čemu je riječ). Glavni nedostatak im je određen već prije spomenutom namjenom (prikazom podataka), pa se u praksi koriste nešto rjeđe, osim ako je dovoljno da kontrola zaista samo prikazuje datum ili vrijeme. Zato se s navedene dvije kontrole više nećemo baviti. Ako njihova ograničenja zadovoljavaju vaše planove u izradi aplikacija, jednostavno ih postavite na neki od standardnih rasporeda kontrola i zaboravite na njih.
U slučaju da je potrebno omogućiti nekakav oblik interakcije korisnika aplikacije u pogledu odabira datuma i/ili vremena, onda je bolje upotrijebiti kontrole pod nazivom DatePicker i TimePicker. Njihovo postavljanje na osnovni raspored kontrola može se napraviti prema slijedećem primjeru.
Prva (gornja) kontrola zadužena je za prikaz, odnosno odabir datuma, a donja to isto radi s vremenom, kao što se to može provjeriti na priloženoj slici uz tekst. Kad se tome pridoda programski kod naveden u nastavku zadužen za podešavanje početnih vrijednosti kontrola, dobije se sasvim funkcionalno korisničko sučelje. Najveći nedostatak ove grupe kontrola je njihova relativna nezgrapnost. Drugim riječima jednostavno su prevelike za intenzivno korištenje, naročito ako koristite uređaj s relativno skromnom rezolucijom zaslona. Ako to predstavlja nepremostivu prepreku možete se snaći i sami te napraviti vlastite i bitno manje kontrole. package Hello.Android; import android.app.Activity; import android.os.Bundle; import android.widget.DatePicker; import android.widget.TimePicker; public class HelloActivity extends Activity { /** Called when the activity is first created. */ @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main);
DatePicker dp = (DatePicker)this.findViewById(R.id.datePicker); dp.init(2010, 11, 13, null); TimePicker tp = (TimePicker)this.findViewById(R.id.timePicker); tp.setIs24HourView(true); tp.setCurrentHour(new Integer(10)); tp.setCurrentMinute(new Integer(10)); } }
Korištenje izbornika Osim sasvim jednostavnih uradaka većina aplikacija podržava neki oblik sustava izbornika namijenjen izboru svih operacija koje nudi aplikacija. Ni Android platforma po tome nije nikakav izuzetak. Zapravo mogli bi reći da vrijedi čak suprotno – programeru je na raspolaganju nekoliko različitih sustava izbornika, a na njemu je odluči koji od njih najviše odgovara potrebama konkretne aplikacije. Dok ste neke od dostupnih sustava izbornika već susretali na drugim operativnim sustavima u vrlo sličnom obliku, Android nudi i neke novosti na ovom području, zbog čega ćemo se izbornicima pozabaviti u dva broja časopisa. Po običaju krećemo od najjednostavnijeg oblika izbornika, za čiju pojavu u aplikaciji je zadužen isključivo programski kod nalik na onaj pridodan na kraj prethodnog projekta za prikaz datumski i vremenski orijentiranih kontrola (funkcija onCreateOptionsMenu). Navedeni naziv funkcije je obavezan i ujedno povezan s odgovarajućom aktivnosti u programu. package Hello.Android; import android.app.Activity; import android.os.Bundle; import android.view.Menu; import android.widget.DatePicker; import android.widget.TimePicker; public class HelloActivity extends Activity { /** Called when the activity is first created. */ @Override public void onCreate(Bundle savedInstanceState)
{ super.onCreate(savedInstanceState); setContentView(R.layout.main); DatePicker dp = (DatePicker)this.findViewById(R.id.datePicker); dp.init(2010, 11, 13, null); TimePicker tp = (TimePicker)this.findViewById(R.id.timePicker); tp.setIs24HourView(true); tp.setCurrentHour(new Integer(10)); tp.setCurrentMinute(new Integer(10)); } public boolean onCreateOptionsMenu(Menu menu) { super.onCreateOptionsMenu(menu); menu.add(0 // Group ,1 // item id ,0 //order ,”append”); // title menu.add(0,2,1,”edit”); menu.add(0,3,2,”clear”); return true; } } Rezultat izvođenja dodatnog programskog koda su tri opcije izbornika, koje se pojavljuju na samom dnu zaslona). Kao što to pokazuje prethodni primjer dodavanje svake od opcija izbornika zahtijeva navođenje četiri parametra.To su redom oznaka grupe, oznaka opcije izbornika, redoslijed opcije u okviru izbornika, te tekst koji se prikazuje na samoj opciji izbornika. Prve tri opcije su brojčane, a četvrta je iz sasvim razumljivih razloga tekstualna. Zadnja od nabrojenih opcija može se u programskom kodu za generiranje izbornika zadati izravno, kao što je to slučaj u
prethodnom primjeru, ili se odgovarajuća vrijednost može unaprijed pripremiti u resursnoj datoteci. Istaknimo kako nije uvijek potrebno navoditi baš sve brojčane vrijednosti, nego se umjesto njih može upotrijebiti vrijednost Menu.None. Ako je potrebno opcije izbornika u aplikaciji grupirati u više od jedne grupe, onda se to rješava navođenjem različitih oznaka grupe prilikom zadavanja naredbi za stvaranje opcija izbornika. Takva podjela izbornika na dvije grupe prikazana je u slijedećem segmentu programskog koda, kojeg treba umetnuti u program umjesto istoimene funkcije iz prethodnog kompletnog primjera koda. Kako će izgledati dobijeni rezultat može se vidjeti na priloženoj slici uz tekst. public boolean onCreateOptionsMenu(Menu menu) { //Group1 int group1 = 1; menu.add(group1,1,1,”g1.item1″); menu.add(group1,2,2,”g1.item2″); //Group2 int group2 = 2; menu.add(group2,3,3,”g2.item1″); menu.add(group2,4,4,”g2.item2″); return true; } Kao što smo to već objasnili ranije, prethodne naredbe izazivaju samo prikaz izbornika na zaslonu uređaja, ali pritisak na te izbornike trenutno ne izaziva baš nikakvu reakciju, jer jednostavno nedostaje odgovarajućeg programskog koda za tu namjenu. To je tema kojom ćemo se pozabaviti u slijedećem broju, baš kao i dodavanjem slika na opcije izbornika, kako bi se postigao što bolji vizualni dojam u vlastitoj aplikaciji. U ostatku današnjeg teksta navest ćemo karakteristike preostalih vrsta izbornika dostupnih na Android platformi. Prva vrsta su takozvani prošireni izbornici. Ova vrsta izbornika nastaje automatski, ako programer „pretjera“ s brojem opcija osnovnog izbornika. U tom slučaju se kao opcija izbornika automatski prikazuje vrijednost More, a njezinim odabirom korisnik aplikacije može stići do početno skrivenih opcija izbornika. Jedno od ograničenja proširenih izbornika je u tome što ne dozvoljavaju prikaz slike, pa zato prilikom pripreme izbornika treba paziti da se na istom mjestu u aplikaciji ne pojave i trešnje i višnje, to jest opcije izbornika sa slikama i one bez slika.
Kod dodavanja ikona na opcije izbornika u igri je još nekoliko dodatnih ograničenja osim onog spomenutog u prethodnom odjeljku. Na opciji izbornika s ikonom ne može biti prikazana oznaka njezinog izbora (kvačica), a ako je tekst opcije izbornika nešto duži, onda će biti prikazan samo početni dio. To i nije nelogično – ako odaberete ikonu koja vrlo reprezentativno označava neku operaciju, zašto bi je onda naširoko i opisivali. Prednosti takvog pristupa kod stvaranja višejezičnog sučelja ne trebamo posebno ni isticati.
U slučaju vrlo širokog raspona mogućih operacija u aplikaciji, neke (ili sve) opcije izbornika mogu imati svoje podizbornike. Opcije podizbornika dodaju se programski odgovarajućim metodama što ćemo prikazati u slijedećem nastavku. Za sada istaknimo kako i ova kategorija izbornika ne podržava prikaz ikona, iako se formalno ne javljaju nikakve greška kod takvog pokušaja. Izbornici ovisni o kontekstu predstavljaju posebnu vrstu izbornika čiji izgled se mijenja ovisno o smislu izvođenja pojedinog dijela aplikacije, a aktiviraju se takozvanim dugim pritiskom na neki element korisničkog sučelja. Programer može u vlastitu aplikaciju dodati i standardne sistemske izbornike. Kako se to radi, također ćemo demonstrirati slijedeći put.
9. Korištenje datotečnog sustava Nakon što smo u prošlom nastavku pokazali kako se stvara osnovna vrsta izbornika, danas ćemo objasniti kako program na najednostavniji mogući način putem izbornika odgovara na akcije korisnika. Ujedno ćemo od ovomjesečnog nastavka napraviti malo „ubrzanje“ u izlaganju kako bi u planiranom broju preostalih nastavaka mogli doista i napraviti nekakvu malo složeniju aplikaciju. Ideja je da izloženu materiju prikažemo na međusobno povezani način, kako nakon prolaska kroz čitav serijal ne bi imali niz nepovezanih segmenata znanja o pojedinim dijelovima Android SDK sustava, ali bez mogućnosti njihovog slaganja u smislenu cjelinu. S druge strane, na temelju dosadašnjih nastavaka više ne bi trebali imati previše problema s tim da pronađete gdje se umeću pojedini dijelovi programskog koda. Zato na ovom mjestu nećemo izložiti sve moguće načine stvaranja izbornika i „hvatanja“ operacija korisnika, jer ih ima zbilja podosta, pa bi se izlaganje htjeli mi to ili ne, lako pretvorilo u „prepisivanje“ originalnih uputa. Umjesto toga ćemo u složenijoj aplikaciji koju smo maloprije najavili pokazati brojne dodatne mogućnosti u korištenju. Osnovni oblik reakcije izbornika na djelovanje korisnika priprema se u dva koraka prema slijedećem obrascu. U prvom koraku treba implementirati OnMenuClickListener sučelje. U drugom koraku, koji se izvodi nakon izbora neke od opcija od strane korisnika, poziva se metoda onMenuItemClick(). To je ujedno mjesto gdje se izvodi stvarna obrada događaja – pritiska na neku od opcija izbornika. //korak1 public class MyResponse implements OnMenuClickListener { //… @override boolean onMenuItemClick(MenuItem item) { //izvođenje operacije return true; } } //korak 2 MyResponse myResponse = new MyResponse(…); menuItem.setOnMenuItemClickListener(myResponse);
… Osim osnovnog načina reakcije izbornika na događaje postoji još nekoliko varijanti koje ćemo demonstrirati na složenijoj aplikaciji. U njoj ćemo ujedno pokazati kako se izvornici mogu stvoriti preko odgovarajuće resursne XML datoteke, a ne samo programskim kodom.
Rad s datotekama Svaka malo složenija aplikacija, koja rukuje s korisnim podacima, mora imati mogućnost spremanja podataka iz aplikacije u neko spremište te njihovo vraćanje kad se za tim ukaže potreba. U današnjem nastavku pokazat ćemo kako se navedene dvije operacije izvode pomoću datotečnog sustava ugrađenog u Android SDK. Za to ćemo koristiti dva specijalizirana tijeka podataka – FileOutputStream iFileInputStream. Prvi se koristi za prijenos podataka na relaciji program – datoteka, a drugi u obrnutom smjeru. Ujedno ćemo pokazati dvije dodatne nužne operacije kod takvog postupka. Prva je „skupljanje“ trenutnih vrijednosti različitih Android kontrola upisanih od strane korisnika aplikacije kako bi se imalo što upisati u datoteku, a druga je njihovo ponovno vraćanje iz datoteke i postavljanje na odgovarajuću kontrolu. Pogledajmo prvo kako se izvodi spremanje podataka u datoteku na segmentu programskog koda „izvađenog“ iz jedne manje medicinski orijentirane aplikacije. U ovom trenutku zapravo i nije previše bitno o kakvim se podacima radi. Primijetimo samo da se podaci ne skupljaju isključivo iz tekstualnih nego i iz drugih oblika kontrola, a prije samog spremanja u datoteku se grupiraju u jedan složeniji niz znakova. U njemu su podaci međusobno odvojeni posebnim nizom znakova za odvajanje, kako bi se olakšalo njihovo obnavljanje kod suprotne operacije čitanja iz datoteke.
Spremanje podataka iz aplikacije: Prethodni primjeri koda odnose se na jednostavnu medicinski orijentiranu aplikaciju. private void SpremiPodatkeCritical2() throws IOException { String FILENAME = “PrvaPomocCritical2″; String string = “”; FileOutputStream fos; try { final EditText tmp = (EditText) findViewById(R.id.txtSpol); String tmps = tmp.getText().toString(); if (tmps.length() == 0) tmps = “!!!”; final EditText tmp2 = (EditText) findViewById(R.id.txtTezina); String tmps2 = tmp2.getText().toString(); if (tmps2.length() == 0) tmps2 = “!!!”; final EditText tmp3 = (EditText) findViewById(R.id.txtKrvnaGrupa); String tmps3 = tmp3.getText().toString(); if (tmps3.length() == 0) tmps3 = “!!!”; final EditText tmp4 = (EditText) findViewById(R.id.txtRhFaktor); String tmps4 = tmp4.getText().toString(); if (tmps4.length() == 0) tmps4 = “!!!”; final CheckBox tmp5 = (CheckBox) findViewById(R.id.chkSida); String tmps5 = “N”; if (tmp5.isChecked()) tmps5 = “D”; final CheckBox tmp6 = (CheckBox) findViewById(R.id.chkHepatitisC); String tmps6 = “N”;
if (tmp6.isChecked()) tmps6 = “D”; final CheckBox tmp7 = (CheckBox) findViewById(R.id.chkDonator); String tmps7 = “N”; if (tmp7.isChecked()) tmps7 = “D”; final EditText tmp8 = (EditText) findViewById(R.id.txtAlergija); String tmps8 = tmp8.getText().toString(); if (tmps8.length() == 0) tmps8 = “!!!”; final EditText tmp9 = (EditText) findViewById(R.id.txtDijagnoza); String tmps9 = tmp9.getText().toString(); if (tmps9.length() == 0) tmps9 = “!!!”; final EditText tmp10 = (EditText) findViewById(R.id.txtTerapija); String tmps10 = tmp10.getText().toString(); if (tmps10.length() == 0) tmps10 = “!!!”; final EditText tmp11 = (EditText) findViewById(R.id.txtNapomena); String tmps11 = tmp11.getText().toString(); if (tmps11.length() == 0) tmps11 = “!!!”; string = tmps + “###” + tmps2 + “###” + tmps3 + “###” + tmps4 + “###” + tmps5 + “###” + tmps6 + “###” + tmps7 + “###” + tmps8 + “###” + tmps9 + “###” + tmps10 + “###” + tmps11; fos = openFileOutput(FILENAME, Context.MODE_PRIVATE); fos.write(string.getBytes()); fos.close(); } catch (FileNotFoundException e) { e.printStackTrace(); } }
Istaknimo vrlo važnu činjenicu koju svakako treba uzeti u obzir kod rada s datotečnim sustavom, a to je mogućnost pojave greške. Osnovni niz naredbi za zapis podataka u datoteku: fos = openFileOutput(FILENAME, Context.MODE_PRIVATE); fos.write(string.getBytes()); fos.close(); može ponekad dovesti do pojave greške, ako ni zbog čega drugog onda zbog nedostatka prostora na mediju na kojem se nalazi datotečni sustav. Kako se aplikacija u tom slučaju ne bi počela nekontrolirano ponašati, treba ugraditi bar osnovni mehanizam obrade pogreške u vlastitom kodu, što je ovdje i napravljeno korištenjem standardne try .. catch strukture. Pogledajmo sada kako se koristi suprotni tijek podataka namijenjen čitanju spremljenih podataka. private void VratiPodatkeCritical2() throws IOException { String FILENAME = “PrvaPomocCritical2″; String string1 = “”; setContentView(R.layout.critical2); FileInputStream fis; try { fis = openFileInput(FILENAME); BufferedReader buf = new BufferedReader(new InputStreamReader(fis)); string1 = buf.readLine(); String[] list = TextUtils.split(string1, “###”); final EditText tmp = (EditText) findViewById(R.id.txtSpol); if (list[0].matches(“!!!”)) list[0] = “”; tmp.setText(list[0]); final EditText tmp2 = (EditText) findViewById(R.id.txtTezina); if (list[1].matches(“!!!”)) list[1] = “”;
tmp2.setText(list[1]); final EditText tmp3 = (EditText) findViewById(R.id.txtKrvnaGrupa); if (list[2].matches(“!!!”)) list[2] = “”; tmp3.setText(list[2]); final EditText tmp4 = (EditText) findViewById(R.id.txtRhFaktor); if (list[3].matches(“!!!”)) list[3] = “”; tmp4.setText(list[3]); final CheckBox tmp5 = (CheckBox) findViewById(R.id.chkSida); tmp5.setChecked(false); if (list[4].matches(“D”)) tmp5.setChecked(true); final CheckBox tmp6 = (CheckBox) findViewById(R.id.chkHepatitisC); tmp6.setChecked(false); if (list[5].matches(“D”)) tmp6.setChecked(true); final CheckBox tmp7 = (CheckBox) findViewById(R.id.chkDonator); tmp7.setChecked(false); if (list[6].matches(“D”)) tmp7.setChecked(true); final EditText tmp8 = (EditText) findViewById(R.id.txtAlergija); if (list[7].matches(“!!!”)) list[7] = “”; tmp8.setText(list[7]); final EditText tmp9 = (EditText) findViewById(R.id.txtDijagnoza); if (list[8].matches(“!!!”)) list[8] = “”; tmp9.setText(list[8]); final EditText tmp10 = (EditText) findViewById(R.id.txtTerapija); if (list[9].matches(“!!!”)) list[9] = “”; tmp10.setText(list[9]);
final EditText tmp11 = (EditText) findViewById(R.id.txtNapomena); if (list[10].matches(“!!!”)) list[10] = “”; tmp11.setText(list[10]); fis.close(); } catch (FileNotFoundException e) { final EditText tmp = (EditText) findViewById(R.id.txtSpol); tmp.setText(“$_”); final EditText tmp2 = (EditText) findViewById(R.id.txtTezina); tmp2.setText(“___”); final EditText tmp3 = (EditText) findViewById(R.id.txtKrvnaGrupa); tmp3.setText(“__”); final EditText tmp4 = (EditText) findViewById(R.id.txtRhFaktor); tmp4.setText(“_”); final CheckBox tmp5 = (CheckBox) findViewById(R.id.chkSida); tmp5.setChecked(false); final CheckBox tmp6 = (CheckBox) findViewById(R.id.chkHepatitisC); tmp6.setChecked(false); final CheckBox tmp7 = (CheckBox) findViewById(R.id.chkDonator); tmp7.setChecked(true); final EditText tmp8 = (EditText) findViewById(R.id.txtAlergija); tmp8.setText(“$Alergija”); final EditText tmp9 = (EditText) findViewById(R.id.txtDijagnoza); tmp9.setText(“$Dijagnoza”);
final EditText tmp10 = (EditText) findViewById(R.id.txtTerapija); tmp10.setText(“$Terapija”); final EditText tmp11 = (EditText) findViewById(R.id.txtNapomena); tmp11.setText(“$Napomena”); e.printStackTrace(); } } Ponovno, potrebna je standardna procedura za obradu pogrešaka (throws IOException), jer se može dogoditi da u datotečnom sustavu iz ovog ili onog razloga ne postoji, ili je oštećena datoteka s podacima. Budući da smo prilikom spremanja podatke formatirali tako da se čitava operacija njihovog spremanja izvodi u jednom koraku (što nije obavezno te ovisi o karakteristikama vlastite aplikacije), sada ćemo čitanje također „odraditi“ u jednom koraku, te ujedno razbiti podatke u odgovarajuće polje podataka pomoću naredbe: String[] list = TextUtils.split(string1, “###”); Preostalo je još samo to da se na korištenom rasporedu kontrola unutar aplikacije pronađe odgovarajuća kontrola te da joj se dodijeli točno određena vrijednost pročitana iz datoteke. Za taj postupak koristi se niz findViewById naredbi.
10. Nekoliko standardnih djelova aplikacije Prošli put smo iz nešto složenije medicinski orijentirane Android aplikacije „izvukli“ dio programskog koda zadužen za spremanje podataka te za njihovo ponovno čitanje kad se za tim ukaže potreba. U današnjem nastavku pokazat ćemo još nekoliko karakterističnih dijelova programskog koda, koje uz manje ili veće promjene možete upotrijebiti u vlastitim projektima. Prvo jedan sasvim logičan, ali važan savjet. Svaka složenija Android aplikacija, a naročito ako ona koristi različite sistemske module (kao što je to slučaj u ovom primjeru), zahtijeva uključivanje odgovarajućih biblioteka. Ovisno o načinu oblikovanja korisničkog sučelja i pisanju programskog koda, taj je postupak u najvećoj mogućoj mjeri automatiziran. Međutim, ako se tijekom razvoja u aplikaciji odjednom pojavi čitav niz pogrešaka, postoji dosta velika vjerojatnost da nedostaje (zbog izostanka ili slučajnog brisanja) odgovarajuća import naredba. U nastavku slijedi prikaz kako to prilično komplicirano izgleda u ovom slučaju:
Primjer rasporeda kontrola: Jedan od standardnih dijelova aplikacije za prikupljanje podataka o korisniku. import java.io.BufferedReader; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStreamReader; import java.io.OutputStream; import java.sql.Date; import java.text.DateFormat; import java.util.Calendar; import android.R.bool; import android.R.integer; import android.R.string;
import android.app.Activity; import android.app.AlertDialog; import android.app.PendingIntent; import android.content.Context; import android.content.DialogInterface; import android.content.Intent; import android.content.res.ColorStateList; import android.location.Location; import android.location.LocationManager; import android.os.Bundle; import android.os.Message; import android.os.Messenger; import android.telephony.SmsManager; import android.text.TextUtils; import android.view.View; import android.view.ViewGroup; import android.view.ViewGroup.LayoutParams; import android.widget.Button; import android.widget.CheckBox; import android.widget.CheckedTextView; import android.widget.EditText; U medicinski orijentiranoj aplikaciji čije dijelove koristimo za demonstraciju programskog koda, zbog relativno velike količine prikupljenih podataka o korisniku aplikacije neprikladne za prikaz na samo jednom zaslonu ograničene rezolucije (uobičajene kod mobilnih telefona opremljenih Android sustavom), koristi se više međusobno povezanih rasporeda kontrola, a na svakom od rasporeda upotrijebljene su različite kontrole kako bi se što jednostavnije i preglednije unijeli relevantni podaci. Kako to zaista izgleda na zaslonu Android uređaja možete provjeriti na temelju priloženih slika uz tekst, a dijelovi odgovarajućeg XML koda navedeni su u nastavku.
… … … …
U trenutku prelaska s jednog rasporeda kontrola na drugi postojeći sadržaj kontrola iz starog rasporeda kontrola sprema se za kasnije korištenje, a novi raspored kontrola se popunjava prethodno spremljenim sadržajem (ako takav postoji zbog ranijeg korištenja aplikacije). Obje operacije objašnjene su u prethodnom nastavku serijala. Pokažimo sada kako se programskim kodom prelazi s jednog rasporeda kontrola na drugi. Na svakom osnovnom rasporedu postoje dva gumba za kretanje na slijedeću odnosno prethodnu stranicu (razumljivo osim na prvom i zadnjem). Slijedi primjer korištenja na drugom rasporedu kontrola – na njemu postoji gumb za prelazak na prvi, odnosno na treći raspored kontrola. public void btn3VratiSeClick(View view) { try { SpremiPodatkeCritical2(); } catch (IOException e1) { e1.printStackTrace(); } setContentView(R.layout.critical); try { VratiPodatkeCritical(); } catch (IOException e) { e.printStackTrace(); } } public void btn3DaljeClick(View view) { try { SpremiPodatkeCritical2(); } catch (IOException e1) {
e1.printStackTrace(); } setContentView(R.layout.critical3); try { VratiPodatkeCritical3(); } catch (IOException e) { e.printStackTrace(); } } Kako eventualne pogreške prilikom kretanja kroz osnovne rasporede kontrola ne bi izazvale rušenje programa, prijenos prikaza s jednog rasproeda kontrola na drugi „zamotan“ je u odgovarajuću strukturu za obradu pogreške. Osim prikaza podataka na standardnim rasporedima kontrola, vrlo često je u programu potrebno prikazati i odgovarajuće dijaloške okvire o statusnim informacijama, greškama u radu i slično. U nastavku je naveden primjer programskog koda za prikaz dijaloškog okvira s podacima o autorima programa (ako za to ne namjeravate koristiti poseban raspored kontrola zbog veće vizualne dojmljivosti takvog dijela aplikacije).
Primjer rasporeda kontrola: Drugi standardni dio aplikacije. public void btnPrvaPomocClick(View view) { AlertDialog ad = new AlertDialog.Builder(prvaPomoc.this).create(); CharSequence poruka = “Autor programa \n” ; poruka = poruka + “Crnko Nenad\n\n”; poruka = poruka + “Stručni medicinski suradnik\n”; poruka = poruka + “Fusić Snježana\n\n”; poruka = poruka + “Verzija programa\n”; poruka = poruka + “25.06.2010 23:00:00″; ad.setTitle(“O programu…”); ad.setMessage(poruka); ad.setButton(“Zatvori”, new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface arg0, int arg1) { } }); ad.show(); } U slučaju da vam to negdje zatreba, evo i opće funkcije za otvaranje osnovnog oblika dijaloškog okvira koju uz veće ili manje preinake možete upotrijebiti u vlastitim aplikacija. Ulazni parametri funkcije su poruka koja se prikazuje u okviru dijaloškog okvira te njegovo zaglavlje. private void MsgBox(String Poruka, String VrstaPoruke) {
AlertDialog ad = new AlertDialog.Builder(prvaPomoc.this).create(); ad.setTitle(VrstaPoruke); ad.setMessage(Poruka); ad.setButton(“Zatvori”, new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface arg0, int arg1) { } }); ad.show(); } Navedimo na kraju današnjeg nastavka najsloženiji „komad“ programskog koda zadužen za pripremu i slanje SMS poruke s podacima iz programa u slučaju nezgode. Zbog ograničenja prostora u časopisu ovim dijelom ćemo se nešto detaljnije pozabaviti u slijedećem nastavku serijala. public void btnPosaljiSMSClick(View view) { final Button btnPosaljiSMS = (Button) findViewById(R.id.btnPosaljiSMS); Calendar Kalendar = Calendar.getInstance (); CharSequence mTrenutnoVrijeme = Kalendar.getTime().toString(); mGodina = Kalendar.get(Calendar.YEAR); mMjesec = Kalendar.get(Calendar.MONTH); mDan = Kalendar.get(Calendar.DAY_OF_MONTH); mSati = Kalendar.get(Calendar.HOUR_OF_DAY); mMinute = Kalendar.get(Calendar.MINUTE); mSekunde = Kalendar.get(Calendar.SECOND );
mTrenutnoVrijeme = Integer.toString(mDan) + “.” + Integer.toString(mMjesec) + “.” + Integer.toString(mGodina) + ” ” + Integer.toString(mSati) + “:” + Integer.toString(mMinute) + “:” + Integer.toString(mSekunde); setContentView(R.layout.critical3); try { VratiPodatkeCritical3(); } catch (IOException e1) { e1.printStackTrace(); } final CheckBox tp = (CheckBox) findViewById(R.id.chkGPSPozicija); String pozicija = “”; if (tp.isChecked()) { try { LocationManager locationManager; String context = Context.LOCATION_SERVICE; locationManager = (LocationManager)getSystemService(context); String provider = LocationManager.GPS_PROVIDER; Location location = locationManager.getLastKnownLocation(provider); double lat = location.getLatitude(); double lng = location.getLongitude();
pozicija = ” ” + Double.toString(lat) + ” / ” + Double.toString(lat); } catch (Exception e) { e.printStackTrace(); } } try { final EditText tmp = (EditText) findViewById(R.id.txtSMSPoruka); String tmps = tmp.getText().toString(); if (tmps.length() == 0) { setContentView(R.layout.main); MsgBox(“Nije definiran tekst SMS poruke!”, “Upozorenje”); return; } final EditText tmpbr = (EditText) findViewById(R.id.txtSMSBroj); String tmpsbr = tmpbr.getText().toString(); if (tmpsbr.length() == 0) { setContentView(R.layout.main); MsgBox(“Nije definiran broj za slanje SMS poruke!”, “Upozorenje”); return; }
setContentView(R.layout.main); VratiPodatkeMain(); tmps = tmps + pozicija; SmsManager sm = SmsManager.getDefault(); sm.sendTextMessage(tmpsbr, null, tmps + pozicija, null, null); } catch (Exception e) { MsgBox(e.getMessage(),”Greška”); e.printStackTrace(); } AlertDialog ad = new AlertDialog.Builder(prvaPomoc.this).create(); CharSequence poruka = “Zabilježeno vrijeme slanja SMS poruke za pomoć\n\n” ; poruka = poruka + mTrenutnoVrijeme.toString(); ad.setTitle(“Potvrda operacije”); ad.setMessage(poruka); ad.setButton(“Zatvori”, new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface arg0, int arg1) { } }); ad.show(); btnPosaljiSMS.setText(“SMS poruka: ” + mTrenutnoVrijeme);
try { SpremiPodatkeMain(); } catch (IOException e) { e.printStackTrace(); } }
11. Standardni dijelovi aplikacije Na kraju teksta u prethodnom broju časopisa naveden je malo veći segment programskog koda za izvođenje nekoliko bitnih stvari u programu, ali jednostavno nije bilo dovoljno mjesta za njegovo detaljnije objašnjenje. Zato u današnjem nastavku slijedi malo detaljnija rasprava o korištenim objektima i metodama u tom dijelu aplikacije. Razjasnimo prvo namjenu izdvojenog dijela programskog koda s kraja prethodnog nastavka, kako bi lakše mogli pratiti detalje u nastavku. Ideja je da korisnik aplikacije u trenutku kad doživi nekakvu nezgodu (koja bitno utječe na njegovo zdravstveno stanje) može što jednostavnije i brže poslati SMS poruku na unaprijed definirani broj, kako bi izabranu osobu ili ustanovu obavijestio o svojoj nezgodi. Pretpostavka za izvođenje takvog postupka je da nakon nezgode ostane u svjesnom stanju, kako bi zaista mogao pokrenuti aplikaciju te pritisnuti gumb za slanje SMS poruke. Ako može napraviti tu operaciju, onda može pritisnuti i drugi gumb kako bi zabilježio vrijeme nezgode, jer se tako kod pružanja prve pomoći lako može ustanoviti koliko je vremena doista prošlo od nezgode. To može biti vrlo bitan faktor za poduzimanje različitih operacija nad unesrećenim. Čak i ako korisnik aplikacije u trenutku kad stigne prva pomoć bude u nesvijesti, može se pročitati podatak o trenutku nezgode, kao i drugim bitnim karakteristikama unesrećenog (krvna grupa, kronične bolesti i slično). Te informacije su dostupne i u situaciji kad SMS poruka nije poslana, a nije zabilježen ni trenutak nezgode – bitno je samo da spasitelji malo „pročeprkaju“ po Android mobitelu, jer je on najverojatnije negdje pri ruci. Ostaje još samo odgovor na pitanje zašto su operacije slanja SMS poruke i bilježenja trenutka nezgode razdvojene. Postoje situacije kad SMS poruku, a pogotovo neke njezine dijelove (vidi nastavak teksta) nije moguće ni pripremiti ni poslati, pa se u tom slučaju može zabilježiti samo trenutak nezgode.
LocationManager: Vrlo složen objekt na Android platformi zadužen za dobijanje točne geografske lokacije. Prvi dio programskog koda je najjednostavniji za objašnjavanje jer služi za obično određivanje točnog vremena nakon pritiska korisnika na odgovarajući gumb aplikacije. To vrijeme se trajno pamti kako bi ga spasitelji mogli naknadno očitati. Ovaj segment programskog koda „zamotan“ je u standardnu rutinu za obradu pogreške, u slučaju da se dogodi nekakav problem tijekom izvođenja aplikacije. public void btnPosaljiSMSClick(View view) { final Button btnPosaljiSMS = (Button) findViewById(R.id.btnPosaljiSMS); Calendar Kalendar = Calendar.getInstance (); CharSequence mTrenutnoVrijeme = Kalendar.getTime().toString(); mGodina = Kalendar.get(Calendar.YEAR); mMjesec = Kalendar.get(Calendar.MONTH); mDan = Kalendar.get(Calendar.DAY_OF_MONTH); mSati = Kalendar.get(Calendar.HOUR_OF_DAY); mMinute = Kalendar.get(Calendar.MINUTE);
mSekunde = Kalendar.get(Calendar.SECOND ); mTrenutnoVrijeme = Integer.toString(mDan) + “.” + Integer.toString(mMjesec) + “.” + Integer.toString(mGodina) + ” ” + Integer.toString(mSati) + “:” + Integer.toString(mMinute) + “:” + Integer.toString(mSekunde); setContentView(R.layout.critical3); try { VratiPodatkeCritical3(); } catch (IOException e1) { e1.printStackTrace(); } final CheckBox tp = (CheckBox) findViewById(R.id.chkGPSPozicija); Da bi SMS poruka koja se šalje na unaprijed definirani telefonski broj bila što korisnija, ideja je da njezin dio bude točna geografska lokacija s koje je poruka poslana, kako bi se što brže i jednostavnije došlo do unesrećenog korisnika aplikacije. Ako mobilni telefon (ili neki drugi uređaj koji se temelji na Android platformi) u sebi sadrži odgovarajući hardverski dio za dobijanje takvog podatka, onda slijedeći dio programskog koda koristi Android objekt LocationManager za dobijanje potrebnog geolokacijskog podatka. String pozicija = “”; if (tp.isChecked()) { try { LocationManager locationManager; String context = Context.LOCATION_SERVICE; locationManager = (LocationManager)getSystemService(context);
String provider = LocationManager.GPS_PROVIDER; Location location = locationManager.getLastKnownLocation(provider); double lat = location.getLatitude(); double lng = location.getLongitude(); pozicija = ” ” + Double.toString(lat) + ” / ” + Double.toString(lat); } catch (Exception e) { e.printStackTrace(); } } Prethodne naredbe sadrže još nekoliko naredbi za formatiranje podataka o geografskoj lokaciji, kako bi podaci u okviru poruke bili prikazani na što čitljiviji podaci razumljiv spasiteljima. Kao i obično, bitno je da takv dio aplikacije podložan pogreškama bude obuhvaćen u strukturu za obradu pogrešaka. Zahtijevani podatak može u nekom trenutku jednostavno biti nedostupan. Na primjer, izvor GPS podataka je uništen solarnom bakljom. Dobro – malo se šalimo, mnogo je vjerojatniji neki drugi uzrok problema, iako prema najavama nekih stručnjaka 2012 godine to možda uopće više neće biti samo šala. LocationManager je vrlo složen objekt na Android platformi pa njegovo detaljno opisivanje prelazi okvire ovog teksta. Osnovni primjer prikazan u prethodnom dijelu programskog koda, trebao bi vam poslužiti kao vodič za dodatno istraživanje pratećih uputa o Android SDK sustavu. Nakon što su pripremljeni svi potrebni podaci o geografskoj lokaciji, preostaje još samo njihovo spajanje s unaprijed definiranim fiksnim dijelom SMS poruke, te slanje poruke na prije upisani mobilni broj. U slučaju da navedena dva podatka nisu pripremljena, onda se korisniku aplikacije javlja odgovarajuća poruka kako bi se riješio problem. Za to se koristi funkcija o čijoj smo namjeni i djelovanju raspravljali u jednom od prethodnih nastavaka serijala. Sasvim je jasno da kritična situacija, u kojoj se može naći korisnik aplikacije, nije baš idealan trenutak da aplikacija javi kako smo u fazi njezinog punjenja početnim podacima zaboravili navesti neki detalj (fiksni dio SMS poruke ili odredišni broj). Otprilike se radi o istoj situaciji kao kad bi vaš najnoviji automobil (dostupan uz mjesečnu ratu od svega 500 kn, ali uz učešće od 30 posto i ostatak vrijednosti od 30 posto – kako to danas nude sitnim slovima neki oglasi na koje se skoro navukao i autor ovih redova), u trenutku hitnog kočenja javio nekakvu poruku da to ne može ili ne želi napraviti. Rješenje problema je vrlo jednostavno. Nakon upisivanja svih potrebnih podataka u aplikaciju na samom početku njezina korištenja, treba poslati probnu poruku te provjeriti je li zaista sve u redu.
try { final EditText tmp = (EditText) findViewById(R.id.txtSMSPoruka); String tmps = tmp.getText().toString(); if (tmps.length() == 0) { setContentView(R.layout.main); MsgBox(“Nije definiran tekst SMS poruke!”, “Upozorenje”); return; } final EditText tmpbr = (EditText) findViewById(R.id.txtSMSBroj); String tmpsbr = tmpbr.getText().toString(); if (tmpsbr.length() == 0) { setContentView(R.layout.main); MsgBox(“Nije definiran broj za slanje SMS poruke!”, “Upozorenje”); return; } setContentView(R.layout.main); VratiPodatkeMain(); tmps = tmps + pozicija; SmsManager sm = SmsManager.getDefault(); sm.sendTextMessage(tmpsbr, null, tmps + pozicija, null, null); } catch (Exception e)
{ MsgBox(e.getMessage(),”Greška”); e.printStackTrace(); } AlertDialog ad = new AlertDialog.Builder(prvaPomoc.this).create(); CharSequence poruka = “Zabilježeno vrijeme slanja SMS poruke za pomoć\n\n” ; poruka = poruka + mTrenutnoVrijeme.toString(); ad.setTitle(“Potvrda operacije”); ad.setMessage(poruka); ad.setButton(“Zatvori”, new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface arg0, int arg1) { } }); ad.show(); Na kraju cijelog postupka prikazuje se točno vrijeme slanja poruke. Ne treba posebno ni napominjati da se svi podaci iz prethodne operacije spremaju u odgovarajuća „spremišta“ u mobilnom telefonu, kako bi i kasnije bili dostupni prema potrebi. btnPosaljiSMS.setText(“SMS poruka: ” + mTrenutnoVrijeme); try { SpremiPodatkeMain(); } catch (IOException e) { e.printStackTrace(); }
} Na temelju svega dosad napisanog u ovom te u prethodnih nekoliko brojeva, već bi trebali biti u mogućnosti sami izrađivati relativno složene Android aplikacije. Međutim, još uvijek nismo završili serijal, jer nam je preostala demonstracija korištenja nekoliko bitnih tehnika kao što je dobro poznati Google Maps, preuzimanje podataka s ugrađenih senzora, korištenje dodatnih grafičkih i zvučnih mogućnosti te još poneka zanimljivih sitnica. Ostalo je još dosta zanimljivog materijala za slijedećih nekoliko nastavaka, posebno ako sve te dijelove uz dodatak već obrađenih želimo kreativno povezati u prave aplikacije.
LocationManager: Vrlo složen objekt na Android platformi zadužen za dobijanje točne geografske lokacije. Budući da smo u zadnjih nekoliko brojeva „vadili“ dijelove programskog koda iz relativno složene aplikacije, nismo na pratećem digitalnom mediju objavljivali dijelove projekta. Od slijedećeg puta ponovo se vraćamo na staru dobru praksu korištenja pratećeg medija uz časopi, kako se ne bi trebali sami mučiti s prekucavanjem manjih ili većih dijelova programskog koda u korisničko sučelje vlastitog računala.
12. Alternativni pristup razvoju aplikacija U prethodnih desetak (i još malo više) nastavaka serijala o Android programiranju pokazali smo dosta toga što vam može pomoći kod razvoja vlastitih aplikacija – počevši od instalacije svih potrebnih alata na vlastito računalo pa sve do razvoja standardnih dijelova složenijih aplikacija. U međuvremenu se uređaji bazirani na Androidu (telefoni, ali i „tabletići“ te drugi mobilni uređaji) sve bolje prodaju širom svijeta, tako da razvoj aplikacija za ovu platformu sigurno neće biti uzaludan napor. Iako ćemo se u slijedećih nekoliko nastavaka serijala pozabaviti s još nekoliko naprednijih programerskih tehnika, ovaj put ćemo se malo detaljnije osvrnuti na alernativni (čitaj bitno jednostavniji) način za razvoj aplikacija, također nastao u radionicama istog proizvođača. Na kraju krajeva među čitateljima časopisa sigurno ima onih s vrlo dobrim idejama za razvoj novih aplikacija, ali im se korištenje Google SDK alata ipak čini malo prekompliciranim. Srećom, Googleovi inženjeri intenzivno rade na nešto drugačijem pristupu čitavoj stvari, pa ćemo vas u današnjem nastavku upoznati s njihovim najnovim uradkom za tu namjenu. App Inventor for Android je naziv za alat namijenjen malo manje spretnim programerima dizajniranim tako da omogućava vizualno orijentirani razvoj različitih Android aplikacija izravno u pregledniku. Zbog toga je pisanje programskog koda gotovo u potpunosti izbačeno iz alata te zamijenjeno nečim genijalno preglednim. Ako ste ipak zainteresirani za programiranje, onda vam ovaj alat zapravo i ne treba, jer već imate dobro poznati Android SDK. Iako u trenutku pisanja teksta (prema tvrdnjama iz samog Googlea) alat još uvijek ne podržava sve što je zamišljeno (još uvijek se nalazi u beta fazi razvoja) već sada se pomoću njega mogu napraviti zanimljive i korisne aplikacije. Googleovi inženjeri naglašavaju kako se trenutni problemi prije svega odnose na područja instalacije upravljačkih uređaja, prijenosa dijelova razvojnog alata Java na računalo te distribuciju same aplikacije na odredišni mobilni uređaj, odnosno postavljanje različitih postavki korištenja aplikacije na tom uređaju. Zato se u trenutnoj fazi razvoja alata od zainteresiranih korisnika traži da pripreme što detaljnije povratne informacije o korištenju alata, kako bi se što prije prevladali svi uočeni problemi.
Priprema računala za razvoj: Mogu se koristiti različite kombinacije operativnih sustava i preglednika. Razvoj vlastitih aplikacija u alatu App Inventor for Android započinje pripremom vlastitog računala za takav zadatak. Za razliku od Microsofta ili Applea poznatih po ograničavaju razvoja na vlastiti hardver i/ili softver, Googleov razvojni tim kontinuirano podržava sve najpopularnije platforme (Windows, Mac i Linux). Zato nije ni čudo da se Android polako, ali sigurno, probija prema samom vrhu popularnosti na području mobilnih platformi. Nastavak teksta, te prije svega prateće slike) podrazumijevaju razvoj vlastitih aplikacija u Google Chrome pregledniku na Windows računalu, ali iz prije navedenih razloga ne bi trebali imati previše problema ni u razvoju aplikacija na nekoj drugoj konfiguraciji. Prvi korak u pripremi računala je preuzimanje odgovarajućeg programa za upravljanje pripremom razvojne konfiguracije. Ovaj program može se slobodno preuzeti usmjeravanjem preglednika na web adresuhttp://appinventor.googlelabs.com/learn/setup/setupwindows.html Nakon preuzimanja instalacijskog programa treba ga instalirati na računalo te podesiti parametre ciljnog mobilnog uređaja. U trenutnoj fazi razvoja alata podržano je izravno svega nekoliko uređaja poput T‐Mobile G1 ili T‐Mobile myTouch, dok se za ostalo „očvrsje“ treba pomučiti malo više te napraviti manja ili veća podešavanja na samom telefonu. Budući da je ovaj postupak ovisan o samom telefonu, kao takav prelazi okvire napisanog teksta. Sve potrebne informacije možete pronaći slijedeći odgovarajuće linkove na prije navedenoj web adresi.
Početak rada na aplikaciji: Započinje stvaranjem projekta – u ovom slučaju HelloPurr.
Izrada prve aplikacije U nastavku teksta opisat ćemo izradu prve aplikacije prema Googlevoj pratećoj dokumentaciji. Za razliku od uobičajenog Hello World primjera koji samo prikazuje dvije riječi na zaslonu, Googleov početni primjer odmah koristi i audio/video podatke, to jest prikazuje sliku te reproducira zvuk. Zato kao početni korak u izradi aplikacije treba skinuti jednu sliku u .png formatu, odnosno jednu zvučnu datoteku u.mp3 formatu. Umjesto onih koje nudi Google za testiranje razvojnog alata, možete upotrijebiti svoje vlastite, ali za sada ćemo se držati priložene „kuharice“. Razvojni alat pokrećete postavljanjem preglednika na adresu http://appinventor.googlelabs.com. Da bi se moglo prijeći na razvoj same aplikacije potrebno je da korisnik ima odgovarajući google email korisnički račun. Ako ga još nemate, ovo je prilika da ga stvorite. Kad obavite tu formalnost, pojavljuje se stranica namijenjena pripremi novih aplikacija, odnosno administriranju postojećih. Budući da pripremate svoj prvi projekt, izaberite opciju New na vrhu stranice te upišite naziv aplikacije HelloPur.
Razvojna okolina: Vrlo je jednostavna i namijenjena korisnicima koji nisu profesionalni programeri. Kao rezultat izvođenja prethodne operacije pojavljuje se glavna stranica razvojnog alata namijenjena izradi aplikacije (vidi prateće slike uz tekst). Sve izgleda vrlo jednostavno, ali je sasvim dovoljno za korisnike kojima je namijenjena – neprofesionalnim programerima s dobrim idejama za vlastite aplikacije. U lijevom dijelu stranice nalaze se različite grupe kontrola namijenjene iskorištavanju brojnih mogućnosti Android sustava. Tijekom razvoja prve aplikacije bit će nam potrebne svega dvije kontrole: Button iLabel. Jednostavnom operacijom povlačenja postavite in na središnji dio stranice namijenjen simuliranju zaslona mobilnog uređaja. Kontrole postavite jednu ispod druge, a onda je preostalo da im izmijenite nekoliko svojstva, kako bi dobili izgled sučelja prikazan na jednoj od
pratećih slika uz tekst. Kontroli Button potrebno je obrisati početni tekst prikazan na kontroli (svojstvo Text) te učitati prije spomenutu sliku kitty.png (svojstvo Image). Kontroli Label potrebno je postaviti boju pozadine na plavu (svojstvo BackgroundColor), povećati veličinu pisma na 30 (svojstvo FontSize), te upisati novi tekst „Pet the Kitty“. Svojstvo koje se koristi za zadnju operaciju već znate s prve kontrole. Sve to se izvodi u prozoru Properties na desnoj strani osnovne stranice.
Postavljanje prve kontrole: Izvodi se običnim povlačenjem kontrole na centralni dio koji predstavlja zaslon mobilnog uređaja. Na ovom stupnju razvoja aplikacije u nju je dodana slika, ali još uvijek ne i zvučni zapis. Zato je potrebno u aplikaciju povući još jednu kontrolu (Sound iz grupe Media), a onda pomoću gumba na dnu stranice dodati prije spomenutu mp3 datoteku (meow.mp3). Ovim potezom sučelje je u potpunosti dovršeno s dizajnerske strane, ali je za kompletiranje aplikacije potrebno napraviti još nešto. Da bi se tijekom izvođenja aplikacije pritiskom na sliku umiljate mačkice izazvalo njezino glasanje, to jest reprodukcija mpr datoteke, potrebno je ipak „napisati mali program“. Prethodnu tvrdnju smo stavili u znake navoda, jer je za razliku od drugih vizualno orijentiranih sučelja, koja u konačnici ipak zahtijevaju prilično znanje programiranja, Google ovdje stvarno napravio korak naprijed. Na vrhu osnovne stranice potrebno je kliknuti na opciju Open the Block Eidtor, a ako ste to napravili prvi put, pričekati određeno vrijema kako bi se na vaše računalo instalirala dodatna komponenta za „pisanje programskog koda“. Evo ponovno navodnika, a konačno i objašnjenja zašto. Kad se otvori popis svih dostupnih događaja, oni su prikazati u obliku svojevrsne slagalice. Potrebni događaj u kontekstu nekog dijela aplikacije potrebno je jednostavno „spariti“ s pravom operacijom, što se izvodi običnom operacijom povlačenja. U konkretnom slučaju potrebno je događaj Button1.Click povezati s operacijom Sound1.Play i to je to. Koliko to efektno izgleda možete provjeriti na priloženoj slici ili isprobati sami. Bravo Google!
Prozor Properties: Koristi se za izmjenu različitih svojstava označene kontrole. Preostalo je još samo da isprobate aplikaciju na stvarnom hardverskom uređaju tijekom instalacije povezanim s razvojnim alatom, ili na odgovarajućem softverskom emulatoru. Na kraju je pomoću operacijePackage for Phone moguće napraviti i distribucijski oblik aplikacije. Priznajte da nije bilo komplicirano, iako nismo baš detaljno opisivali način promjene svojstava. Ipak bi ovaj tekst trebali pratiti čitatelji s bar početnim poznavanjem programiranja, tako da ne bi trebao biti problem izvesti tako elementarne operacije u dizajnu aplikacije. Pomoću alata App Inventor for Android (iako je još uvijek u fazi beta verzije) mogu se napraviti znatno složenije aplikacije u što se možete uvjeriti i sami nakon malo vježbe.
Dodavanje programskog koda: Zaista se izvodi na vizualno efektan način.
Izvođenje programa: Osim na samom uređaju, moguće je i u odgovarajućem emulatoru.
13. Alternativni pristup razvoju aplikacija II
Prošli put smo demonstrirali osnove korištenja Googleovog alternativnog alata za razvoj Android aplikacija namijenjenog neprogramerima i „malo manje spretnim programerima“. App Inventor for Android, kako je njegov naziv, pokazao se sasvim prikladnim za stvaranje elementarne Android aplikacije (nešto slično klasičnom Hello World primjeru), a danas ćemo probati prikazati da je upotrebljiv za bitno složenije projekte. Odgovorimo prvo na nekoliko najvažnijih pitanja povezanih s korištenjem alata na razvoju složenijih projekata. Najvažnije pitanje koje se nameće samo po sebi je potencijalna složenost dovršene aplikacije. Tu odmah treba biti izravan te reći da se pomoću alata App Inventor for Android ne može napraviti baš sve što i s službenim razvojnim alatom, ali da se može puno toga – može se. Osim brojnih komponenti za razvoj različitih dijelova sučelja (što smo djelomice pokazali u u prošlom uvodnom tekstu o alatu), na raspolaganju su najvažnije programske strukture poput foreach, while, if‐else (iako u nešto slikovitijem obliku nego je to uobičajeno u programskim jezicima), a moguća je i komunikacija s web servisima te svojevrsnim spremištem podataka. Od važnijih tehnologija karakterističnih za mobilne uređaje današnjice, trenutno nije podržan samo Bluetooth, ali se prema tvrdnjama proizvođača intenzivno radi i na tom segmentu.
Basic komponente: Predstavljaju osnovne grafičke elemente aplikacije. Ako vam slučajno ni sve nabrojano nije dovoljno za izradu vlastite aplikacije, onda alat skoro neograničeno možete nadopunjavati izradom vlastitih komponenti u Javi. To znači da morate ipak biti nešto vještiji u programiranju, a onda se neminovno postavlja pitanje zašto ne bi sve skupa ipak programirali u standardnom SDK razvojnom sustavu. Ako pomoću alata App Inventor for
Android možete sami odraditi veći dio projekta, onda ima smisla da za manji nedostajući segment vlastite aplikacije angažirate Java programera da vam pomogne. Trenutno dva najveća nedostatka alata odnose se na nemogućnost izravne objave aplikacije na globalnom tržištu Android aplikacija (Android Market), te ograničenost aplikacije na samo jedan prikaz (raspored kontrola). Google obećava kako će prvi problem biti uskoro riješen pa se zato njime nećemo previše baviti. Napišimo zato nekoliko riječi o drugom problemu. Na trenutnom stupnja razvoja alata ne može se izvoditi prebacivanje između više različitih vrsta prikaza ili rasporeda kontrola. To na prvi, drugi i treći pogled predstavlja zbilja veliko ograničenje u razvoju aplikacija, ali ga je ipak moguće prevazići jednim od slijedeća dva trika. 1. Naizmjeničnim „paljenjem i gašenjem“ kontrola, to jest izmjenom vidljivosti različitih komponenti postavljenih na jedini dostupni prikaz kontrola. 2. Međusobnim višestrukim povezivanjem više App Inventor for Android aplikacija, od kojih svaka može imati različite rasporede kontrola na osnovnom zaslonu. Kad su prije koje desetljeće nešto slično mogli raditi autori složenih igara na strojevima poput ZX Spectruma ili Commodorea 64 te kasetofonom kao uređajem vanjske memorije, nema nikakvog razloga zašto se to ne bi moglo napraviti i danas sa znatno modernijim hardverom.
Media komponente: Komponente za upravljanje različitim multimedijalnim dijelovima mobilnog uređaja. Iako slijedeća vijest nema nikakve veze s prethodnom točkom, današnjim tekstom, pa čak ni cijelim serijalom u cjelini, ipak ću je spomenuti na ovom mjestu, ako je do sada već niste sami negdje pročitali. Kultni Commodore 64 je prije kratkog vremena doživio svoju inkarnaciju s istim izgledom izvana, ali ultramodernim hardverom i softverom iznutra. Narudžbe se mogu napraviti već sada, a isporuka se očekuje u petom mjesecu. Morao sam to jednostavno spomenuti – prve ljubavi se teško zaboravljaju, makar to bila i računala.
Vratimo se sada ponovo današnjoj temi. Ključne dijelove aplikacije možemo podijeliti u dvije velike skupine: 1. Komponente ili kontrole 2. Blokove Komponente su osnovni grafički dijelovi aplikacije, a međusobno se osim po izgledu razlikuju prije svega po svojoj namjeni. Osnovna grupa komponenti pod nazivom Basic obuhvaća zbilja osnovne komponente karakteristične za moderna korisnička sučelja poput gumbi, oznaka i slika. Ako ste ikad probali napisati bilo kakvu aplikaciju u nekom modernijem razvojnom alatu, trebali bi znati o čemu je riječ, pa se zato i nećemo previše baviti njihovim karakteristika. U istoj grupi kontrola nalaze se još dvije složenije kontrole, a one ipak zahtijevaju poneku dodatnu riječ. To su Canvas i TinyDB.
Animation komponente: Preduvjet za njihovo korištenje je postojanje komponente Canvas. Kontrola Canvas zamišljena je kao dvodimenzionalno područje za crtanje likova pomoću programskog koda, odnosno za pomicanje sličica („sprites“). Budući da je to isto područje osjetljivo na dodir, sasvim je razumljivo da predstavlja temeljni dio većine različitih igara razvijenih u ovom alatu. Svaka od lokacija na komponenti Canvas označava se uobičajenim matematičkim zapisom za dvodimenzionalne površine – kao koordinate x i y. O važnosti navedene kontrole u razvoju aplikacija najbolje govori činjenica da je u zadnjoj reviziji alata od strane Googlea s kraja trećeg mjeseca, veliki dio poboljšanja dodan upravo u Canvas kontrolu. Neka od tipičnih svojstava i metoda Canvas kontrole, čija imena govore sama za sebe su: BackgroundImage, LineWidth, Touched(number x, number y, boolean touchedSprite), Clear(), DrawLine(number x1, number y1, number x2, number y2), DrawCircle(number x, number y, number r).
Tijekom pisanja igara kontrola Canvas se vrlo često upotrebljava u kombinaciji s kontrolom Clock kako bi se osiguralo odvijanje operacija u zadanim vremenskim intervalima. Spomenimo na ovom mjestu kako kontrola Clock ujedno pripada grupi „nevidljivih“ kontrola, što znači da se ne vidi tijekom izvođenja aplikacije, ali mora biti nacrtana na osnovnoj formi kako bi se mogle koristiti njezine mogućnosti. Kontrola TinyDB namijenjena je trajnom spremanju podataka iz aplikacije u mobilni uređaj. Prilikom svakog prekida izvršavanja aplikacije gubi se sadržaj svih korištenih kontrola te se ponovo puni inicijalnim vrijednostima kod slijedećeg pokretanja aplikacije. Ako prilikom novog pokretanja aplikacije treba krenuti od njezinog zadnjeg stanja, onda treba postojati nekakav mehanizam za spremanje vrijednosti iz aplikacije u Android uređaj, te njihovo ponovno čitanje (na primjer, postavke aplikacije, stanje bodova u privremeno prekinutoj igri i slično). Upravo za takvu namjenu zamišljena je kontrola TinyDB, odnosno njezine dvije jedine dostupne metode:
StoreValue(oznaka, vrijednost) Sprema vrijednost (niz znakova ili popis) pod određenim nazivom u spremište na mobilnom uređaju.
GetValue(oznaka) Čita vrijednost sa zadanim nazivom iz spremišta. U slučaju da tražena oznaka ne postoji u spremištu (npr. kod prvog pokušaja čitanja vrijednosti na novom uređaju), onda metoda vraća prazan niz znakova. U slučaju da treba obrisati spremište od starih vrijednosti, onda se to izvodi na telefonu standardnom naredbom Settings → Applications → Manage Applications. U grupi kontrola pod nazivom Media nalazi se 5 komponenti slijedećih naziva: Camera, ImagePicker, Player, Sound i VideoPlayer. Svaka od kontrola zadužena je za upravljanje odgovarajućim hardverskim ili softverskim resursom, pa su u skladu s tim i dodijeljeni nazivi svojstava odnosno metoda (npr. TakePicture ili AfterPicture za kontrolu Camera, odnosno Start, Stop ili Pause za kontroluPlayer). Grupa kontrola Animation te njezine dvije jedine komponente Ball odnosno ImageSprite, koriste se u kombinaciji s prije spomenutom kontrolom Canvas za aplikacije u kojima je potrebno izvoditi različite vrste pokretanja grafičkih objekata (dakle najčešće igre). Na priloženoj slici uz tekst vidi se da je preduvjet za korištenje kontroli iz ove grupe upravo postojanje kontrole Canvas. Pomoću svojstava kontrola poput Interval, Speed ili Rotates upravlja se učestalošću, brzinom i rotacijom „sličica ili loptica“ u vlastitoj aplikaciji. Budući da u jednoj aplikaciji može biti više Canvas kontrola, nema nikakvog razloga da njihovim inteligentnim paljenjem i gašenjem na jednom jedinom zaslonu (prije istaknuto ograničenje trenutne verzije razvojnog alata) napravite prilično kompleksnu igru.
Social komponente: Zadužene su za pristup i korištenje različitih socijalnih podataka iz mobilnog uređaja. Posljednja grupa kontrola koju ćemo spomenuti u današnjem nastavku su kontrole iz grupe Social zadužene za pristup i korištenje različitih socijalnih podataka iz mobilnog uređaja (ContactPicker, EmailPicker, PhoneCall, PhoneNumberPicker, Texting i Twitter). Pomoću ovih kontrola moguće je postići da vlastite aplikacije upravljaju telefonskim pozivima, slanjem sms i/ili email porukama, odnosno korištenjem usluga Twittera (npr. korištenjem metoda poput DirectMessage, RequestDirectMessage ili RequestFriendTimeLine). U slijedećem nastavku napravit ćemo pregled preostalih dostupnih kontrola, a onda napraviti nekoliko složenijih primjera, koji bi trebali prikazati kako ovim alatom doista nije problem brzo napraviti i znatno složenije aplikacije.
14. Alternativni pristup razvoju aplikacija II Danas ćemo se pozabaviti preostalim komponentama dostupnim u Googleovom alatu App Inventor for Android namijenjenom brzom razvoju Android aplikacija. Komponente su razvrstane u nekoliko grupa slijedećih naziva: Sensors, Screen Arrangement, LEGO MINDSTORMS, Other stuff i Not ready for prime time. Krenimo redom.
Sensors komponente: Zadužene su za upravljanje različitim senzorima u mobilnom uređaju.
Sensors komponente Danas je sasvim uobičajeno da pametni telefoni i drugi uređaji temeljeni na Androidu imaju ugrađen manji ili veći broj senzora, koji se mogu vrlo djelotvorno iskoristiti u različitim vrstama aplikacija (najčešće igrama). Zbog toga je razvijeno nekoliko posebnih komponenti za relativno jednostavnu podršku takvoj vrsti hardvera. Sve komponente su nevidljive tijekom izvođenja, ali moraju biti uključene u aplikaciju da bi se mogle iskoristiti njihove mogućnosti. Komponenta AccelerometerSensor zadužena je za interakciju softvera sa senzorom za mjerenje pomicanja uređaja po sve tri osi koordinatnog sustava. Od tuda dolaze nazivi najvažnijih svojstava: XAccel, YAccel, Zaccel. Pomoću svojstva Available programer može provjeriti jesu li navedeni senzor uopće dostupni u uređaju, a svojstvom Enabled upravljati dozvolom korištenja senzora. Događajem AccelerationChanged može se precizno reagirati na pomicanje uređaja po bilo kojoj od navedene tri osi (parametara događaja), dok je nešto „grublji događaj“ Shaking namijenjen mnogo jednostavnijem zadatku – običnoj provjeri „drmanja“ uređajem. Drugi događaj se najčešće može upotrijebiti za efektan prekid izvođenja različitih operacija u aktivnoj aplikaciji. Druga nevidljiva kontrola iz iste skupine je LocationSensor, a namijenjena je dobijanju geografske pozicije mobilnog uređaja, ako je u njega ugrađen odgovarajući GPS prijemnik (svojstvo HasLongitudeLatitude). Softverski je podržano mjerenje nadmorske visine (svojstvo HasAltitude), ako i takva mogućnost postoji u hardveru. Ostalim dostupnim svojstvima može se dobiti vrijednost svake od navedenih tri dimenzija, dok su događaji LocationChanged te StatusChanged zaduženi za reakciju aplikacije na promjene pozicije uređaja u prostoru, odnosno na promjene načina mjerenja pozicije (izravno dobijeni GPS podaci ili podaci dobijeni od mrežnog operatora).
Zadnja komponenta iz grupe OrientationSensor zadužena je za provjeru orijentacije uređaja u prostoru (svojstva Roll, Pitch i Yaw te događaj OrientationChanged). Ova sofverska komponenta se u kombinaciji s pripadajućim senzorom koristi u različitim aplikacijama za promjenu načina prikaza podataka ovisno o promjeni orijentacije uređaja (vodoravni ili vertikalni prikaz podataka).
Screen Arrangement komponente
Screen Arrangement komponente: Koriste se kao „podloga“ za raspored drugih kontrola. Sve tri komponente iz ove grupe (HorizontalArrangement, TableArrangement i HorizontalArrangement) zadužene su za jednostavnije raspoređivanje ostalih komponenti po zaslonu uređaja. Kao što im i nazivi govore, svaka od komponenti je zadužena za jednu vrstu rasporeda osnovnih kontrola. Osim za početno raspoređivanje kontrola sve tri komponente mogu se također iskoristiti za njihovo jednostavnije premještanje ili skrivanje. Dostupna svojstva kontrola su vrlo jednostavna te razumljiva sama po sebi (Visible, Height, Width, Rows i Columns).
LEGO MINDSTORMS komponente Sedam komponenti iz grupe LEGO MINDSTORMS predviđene su za upravljanje različitih dijelovima poznatog Lego kompleta za učenje robotike pomoću nekog od Android uređaja. Iskreno, nismo imali priliku ni zadovoljstvo isprobati kako sve to skupa djeluje u praksi, pa se zato za sada nećemo previše ni baviti ovim dijelom razvojnog alata. Nadamo se da ćemo u ne tako dalekoj budućnosti ipak biti u prilici isprobati simbozu Lego i Google proizvoda.
Other stuff komponente
LEGO MINDSTORMS komponente: Zadužene su za povezivanje s Lego „očvrsjem“. Šaroliko društvo softverskih komponenti iz ove grupe nikako se po svojoj namjeni ne može dovesti u izravnu vezu, zbog čega je cijela grupa dobila naziv koji označava takvu raznolikost. Jedna od najvažnijih komponenti iz grupe je komponenta ActivityStater. Zadužena je za pokretanje nekoliko različitih aktivnosti na uređaju: drugih aplikacija napravljenih u istom alatu ako takve postoje u uređaju (čime se može izbjeći dosta ozbiljno ograničenje o korištenju jednog zaslona ekrana po aplikaciji), aplikacije zadužene za upravljanje kamerom (ako je kamera ugrađena u mobilni uređaj), pretraživanje web sadržaja, postavljanje preglednika na točno određenu web adresu, odnosno postavljenje točno određene lokacije na karti. Zbog toga komponenta podržava različite načine vlastitog pozivanja. Evo primjera iz prateće dokumentacije zaduženog za pretraživanje weba u „potrazi za vampirima“. Action: android.intent.action.WEB_SEARCH ExtraKey: query ExtraValue: vampire ActivityPackage: com.google.android.providers.enhancedgooglesearch ActivityClass: com.google.android.providers.enhancedgooglesearch.Launcher Komponenta BarcodeScanner zadužena je za jednostavno čitanje običnih jednodimenzionalnih, ali i sve popularnijih dvodimenzionalnih bar kodova (korištenjem metode DoScan, svojstva Result i događaj AfterScan). Da je takva komponenta jednostavno neizostavna u modernim softverskim rješenjima, autor teksta može posvjedočiti iz prve ruke. Na nedavno završenoj Microsoftovoj
konferenciji Windays 11 u Rovinju, osim očekivanih mjesta za takvu vrstu označavanja, dvodimenzionalni bar kodovi su se mogli primijetiti i na majicama nekih sudionika. Naoružani Android uređajem te odgovarajućom aplikacijom više ne morate gubiti vrijeme da bi saznali osnovne informacije o vlasniku majice. Umjesto toga u njegovom smjeru jednostavno uperite kameru i pogledate na zaslonu sve što vam želi odati o sebi.
Other stuff komponente: Ostale komponente koje se koriste u razvoju. Dvije komponente sličnog naziva BluetoothServer i BluetoothClient zadužene su za podršku obiju strana koje sudjeluju u Bluetooth komunikaciji (servera i klijenta). Popis dostupnih metoda, svojstava i događaja je zbilja impresivan (bar u usporedni s drugim komponentama iz istog alata), a potrebno je poznavati još poneki detalj Bluetooth tehnologije, tako da se u ovom tekstu jednostavno ne možemo detaljnije pozabaviti njihovim korištenjem. Kako je potpisnik ovih redova u bliskoj prošlosti imao prilike raditi na Bluetooth orijentiranom projektu namijenjenom starim dobrim Java MIDP uređajima, osobno može potvrditi da je korištenje Google tehnologije na istom području bitno jednostavnije. Budući da sami razvojni inženjeri tvrde da se na ovom segmentu razvojnog alata još uvijek intenzivno radi, ipak treba malo sačekati sa završnom ocjenom. Komponenta Notifier omogućava prikaz različitih vrsti obavijesti korisniku aplikacije odnosno trajno bilježenje takvih informacija u svrhu kasnije analize. Za to je pripremljeno nekoliko metoda (ShowMessageDialog, ShowChooseDialog, ShowTextDialog, ShowAlert i LogError) čije korištenje rezultira različitim načinom prikaza informacija korisniku odnosno njihovom bilježenju. Na raspolaganju su također dva događaja: AfterChoosing i ShowChooseDialog, kako bi se moglo ustanoviti što je poduzeo korisnik kao reakciju na prikazane informacije od strane aplikacije. Zadnje dvije komponente iz grupe (SpeechRecognizer i TextToSpeech) zamišljene su kao podrška za izradu govorno orijentiranog korisničkog sučelja u vlastitim Android aplikacijama. Prva kontrola namijenjena je razumijevanju izgovorenog, dok je druga zadužena za suprotan proces –
izgovaranje napisanog teksta. Koliko to sve skupa radi ili ne radi dobro s različitim govornim jezicima možete isprobati sami. Obje komponente su vrlo jednostavne za korištenje, jer se primjena svodi na upotrebu jednostavnih metoda poput GetText, Speek, Country i Language. Spomenimo na ovom mjestu kako se za izgovor napisanog teksta koristi ista Google tehnologija koja je korištena u serijalu o naprednom programiranju Windows aplikacija, objavljenom u više prethodnih brojeva vašeg omiljenog časopisa. Not ready for prime time komponente
Not ready for prime time komponente: Eksperimentalne komponente u intenzivnoj fazi razvoja. U posljednoj grupi komponenti navedene su komponente na čijem razvoju još uvijek intenzivno rade Googleovi razvojni inženjeri, pa su kao takve podložne različitim promjenama dok ne stignu u fazu dovršenog proizvoda. Trenutno su u tu grupu svrstane slijedeće komponente: FusionTablesControl – korištenje kartografskih prikaza u kombinaciji s FusionTables tehologijom. GameClient – povezivanje aplikacija (najčešće igara) s odgovarajućim serverima za „udružene NEzločinačke poduhvate“. SoundRecorder – bilježenje i pohranjivanje zvučnih zapisa. TinyWebDB – komunikacija s web servisima zbog dvosmjerne razmjene podataka. Voting – osnova za buduće glasačke listiće u „Android demokraciji budućnosti“.
Kako su sve nabrojane komponente iz ove grupe u razvoju, za sada se nećemo previše ni baviti njima. Ipak moramo priznati da nas strašno zanima vrlo novi svijet u kojem ćemo praktično trenutno moći odlučivati o bitnim stvarima u zemlji, a ne čekati da to radimo od izbora do izbora. Nažalost, ipak bi se mogli okladiti na prilično velike iznose kako će takvu tehnologiju prije prihvatiti različiti „reality“ spektakli nego državna uprava. Živi bili pa vidjeli. Ovime je završeno predstavljanje najvažnijih segmenata Googleovog razvojnog alata za neprogramere. Preostalo je da pomoću njega probamo napraviti jednu složeniju aplikaciju kao demonstraciju kako različite komponente surađuju u praksi.
15. Izrada složenijih aplikacija Nakon što smo u prošlih nekoliko nastavaka predstavili najvažnije dijelove Googleovog alata za razvoj aplikacija namijenjenog korisnicima neprogramerima, odnosno malo manje vještim programerima, došao je trenutak da pokažemo kako se ti dijelovi zaista koriste u vlastitim aplikacijama. Za razliku od prve demo aplikacije, kad smo vrlo detaljno riječju i slikom opisivali kako se izvode sve operacije potrebne da se dobije dovršena aplikacija, u današnjem nastavku ćemo samo naznačiti glavne smjernice u pripremi aplikacije, a na vama je da probate sami dovesti projekt u funkcionalno stanje. Tako ćemo odmah pripremiti i svojevrsnu vježbanju u korištenju alata. Iako se danas mobilni uređaji koriste za izvođenje više desetaka različitih operacija – od planiranja vlastitog vremena, preko slušanja muzike i gledanja filmova pa sve do igranja različitih vrsta igara, mogućnost izvođenja starog, dobrog telefonskog poziva (ili bar odgovaranja na njega) još uvijek ostaje jedna od najbitnijih namjena većine mobilnih telefona. Zato ćemo u prvom primjeru nešto složenije aplikacije demonstrirati što možemo napraviti u Googlevom razvojnom alatu po tom pitanju, ako ne želimo koristiti već ugrađene mogućnosti u sam uređaj. Pretpostavka za uspješno izvođenje slijedeće aplikacije na konkretnom Android uređaju je da taj uređaj podržava izvođenje telefonskih poziva, a ne samo različite internet orijentirane načine vlastitog korištenja (pregled web stranica, razmjena email poruka i slično). Također, u spremište kontakata u uređaju trebalo bi biti upisano bar nekoliko telefonskih brojeva, a nekima od brojeva trebale bi biti dodijeljenje slike njihovih vlasnika. Čak i ako svi nabrojeni zahtjevi budu zadovoljeni, može se dogoditi da na nekim uređajima primjer ipak ne djeluje kako se očekuje. Razloge treba tražiti u tome što u trenutnoj fazi razvoja alat App Inventor for Android još uvijek nije ni testiran ni optimiziran za sve dostupne uređaje na tržištu. Googleovi razvojni inženjeri obećavaju kako će takve „porođajne muke“ biti riješene u bliskoj budućnosti kad razvojni alat više ne bude u fazi svojevrsnog testiranja. Za uspostavu telefonskog poziva iz Android uređaja, kao što to već znate, treba kreirati novi prazan projekt te mu dodijeliti nekakav naziv koji simbolizira namjenu projekta. U pripremi primjera povezanog s ovim tekstom korišten je naziv VidiPhoneCall, ali nema apsolutno nikakvog razloga da ne odaberete neki drugi mnogo „razumljiviji“ naziv (npr. APC 4MM – Android PhoneCall System for Modern Manager). Od dostupnih Android komponeti u projektu su nam na samom početku
potrebne samo dvije: komponenta PhoneCall iz grupe Social te komponenta Button iz grupe Basic. U nastavku teksta ćemo slične konstrukcije skraćeno pisati Social ‐> PhoneCall, odnosno Basic ‐> Button.
Social ‐> Phone Call: Temeljna komponenta za izvođenje telefonskog poziva iz vlastite Android aplikacije. Svakoj komponenti postavljenoj na osnovni zaslon razvojni alat automatski dodjeljuju naziv sastavljen od naziva komponente te rednog broja takve vrste komponente unutar projekta. U slučaju jednostavnijih projekta takvi nazivi se mogu izravno koristiti za dovršetak projekta, ali dobra praksa iskusnijih programera predlaže njihovo preimenovanje u daleko razumljivije nazive, kako bi se kasnije olakšalo snalaženje u projektu. Što se u nekom projektu koristi više različitih komponenti (to vrijedi i za sve druge razvojne alate), to je važnije imati smislenije nazive, da bi se programer što brže i jednostavnije mogao snaći u naknadnoj analizi i izmjeni programskog koda. Dobro, kod alata App Inventor zapravo ni ne možemo govoriti baš o „pisanju programskog koda“, jer je prije riječ o nećemu nalik slaganju komada slagalice sastavljene od dostupnih događaja i metoda korištenih komponeti, ali nema nikakvog razloga da ignoriramo pravilo o imenovanju komponenti. Preimenovanje komponente postavljene na osnovni zaslon projekta izvodi se njezinim označavanjem, te klikom na gumb u razvojnoj okolini alata. Za potrebe ovog projekta komponentu PhoneCall1 preimenovali smo u TelefonskiPoziv, a komponetu Button1 u UspostaviPoziv. Još jednom ponavljamo – budući da bi rad na ovom projektu trebao ujedno biti vaša samostalna vježba korištenja Googleovog razvojnog alata, nazive komponenti možete izabrati prema vlastitim sklonostima. Za komponentu TelefonskiPoziv može se izmijeniti i početna vrijednost svojstva PhoneNumber na željeni broj pozivatelja (ako se pozivi najčešće upućuju na taj broj), dok komponenti UspostaviPoziv treba izmijeniti svojstvo Text, kako bi zamjena za podrazumijevanu vrijednost Text for Button1preciznije pokazivala namjenu gumba.
U ovom trenutku je dovršeno „crtanje“ korisničkog sučelja, a sad preostaje još samo to da se „napiše odgovarajući programski kod“, odnosno dovrši slagalica u inovativnom Googleovom sučelju za tu namjenu (o čijem korištenju je bilo više riječi u prvom nastavku serijala). Sasvim konkretno – u ovom slučaju potrebno je napraviti povezivanje bloka Click iz kontrole UpostaviPoziv s blokomMakePhoneCall iz kontrole TelefonskiPoziv. Na taj način dovršena je prva verzija aplikacije koja omogućava uspostavu telefonskog poziva iz Android uređaja s upisanim odredišnim brojem nakon što korisnik pritisne kontrolu (gumb) UspostaviPoziv. Djelovanje programa možete (ili ipak ne možete) provjeriti sami na vlastitom komadu Android hardvera, već prema tome kako je on trenutno podržan od strane Googleovih razvojnih inženjera. Na trenutnom stupnju razvoja naše nove aplikacije trebalo bi biti moguće uspostaviti telefonski poziv, ali aplikacija još uvijek „nema pojma“ o podacima zapisanim u bazu kontakata u okviru samog uređaja, nego se svi telefonski brojevi moraju upisivati u cijelosti. Budite iskreni pa priznajte sami sebi koliko često u praksi zaista izvodite operaciju upisivanja broja pozivatelja u odnosu na učestalost biranja dostupnih brojeva iz baze kontakata. Zato aplikaciju treba dodatno proširiti tako da postane „svjesna“ ranije pripremljenih telefonskih brojeva.
Dovršeno sučelje aplikacije za telefoniranje: Omogućava korištenje podataka iz spremišta kontakata u samom uređaju. U drugoj verziji aplikacije ćemo na osnovni zaslon aplikacije dodati još jednu novu kontrolu: Social ‐> PhoneNumberPicker, a onda joj izmijeniti predloženi naziv u IzaberiBroj, odnosno tekst koji se prikazuje na kontroli s početne vrijednosti Text for PhoneNumberPicker1 za hrvatsku verziju aplikacije primjereniji oblik Izaberi broj. Kontrola tipa PhoneNumberPicker predstavlja svojevrsnu verziju običnog gumba, s tom razlikom da pritisak na kontrolu automatski izaziva prikaz podataka iz postojeće baze kontakata u uređaju. Kad smo napisali „prikaz podataka“, onda smo zaista mislili samo na to, jer odabir telefonskog broja iz prikazanih podataka još uvijek nije moguć, bar ne tako dugo dok se ponovo ne pripremi odgovarajuća „slagalica“ za upravljanje izvođenjem programa.
Da bi se na temelju izabranog podatka iz popisa kontakata zaista ostvario telefonski poziv, potrebno je spojiti blok AfterPicking kontrole IzaberiBroj s blokom MakePhoneCall iz kontrole TelefonskiPoziv. Potrebno je napraviti još prijenos odgovarajućeg parametra (izabranog telefonskog broja) između te dvije kontrole, što se izvodi dodatnim vezanjem bloka PhoneNumber kontrole IzaberiBroj s prije navedenim blokom MakePhoneCall. Ovim korakom, ako je sve pravilno izvedeno, trebala bi biti dovršena druga faza u razvoju aplikacije. Sada je aplikacija spremna za izvođenje telefonskih poziva na temelju prije spremljenih podataka u bazu kontakata. U smislu poboljšanja grafičkog izgleda aplikacije moguće je u aplikaciju dodati još poneki detalj. Premda se u trenutnoj verziji broj iz baze kontakata zaista može izabrati kao temelj za telefonski poziv, korisnik aplikacije još uvijek ne može vidjeti o kojem je telefonskom broju riječ. Da ne spominjemo nemogućnost prikaza slike vlasnika telefonskog broja, ako takva postoji u uređaju. Unapređenje korisničkog sučelja aplikacije može se postići tako da se u okviru istog bloka AfterPicking kontrole IzaberiBroj, naprave dva dodatna povezivanja. Blok PhoneNumber iz kontrole IzaberiBroj treba povezati s blokom Text ranije opisanog gumba UspostaviPoziv, a blok Picture iz kontrole IzaberiBroj spojiti s blokom Image, također svojstvom gumba UspostaviPoziv. Navedenim operacijama je aplikacija poboljšana u vizualnom smislu pa osim zahtijevane funkcionalnosti sada posjeduje i odgovarajuće korisničko sučelje. Trenutna verzija aplikacija se i dalje može nadograđivati, pa evo nekoliko ideja koje možete probati napraviti sami: 1. Osim prijenosa broja koji se poziva iz baze spremljenih kontakata, probajte prenijeti još neke podatke na osnovni zaslon aplikacije (prije svega prezime i ime korisnika). Razmislite prvo trebaju li vam kakve dodatne kontrole na sučelju, da bi to zaista mogli napraviti. Ova točka ne bi trebala biti prezahtijevna za realizaciju. 2. Podaci o uspostavljenim pozivima mogli bi se sačuvati za kasniju analizu. Kako je u ovom slučaju riječ o malo zahtijevnijem postupku, o njemu će više riječi biti neki drugi put. Na kraju, ambiciozniji čitatelji mogu probati sami napraviti sličan projekt ispočetka tako da se umjesto uspostave telefonskog poziva izvodi slanje dobre, stare SMS poruke. U tom slučaju temeljnu kontrolu za rad aplikacije (Social ‐> PhoneCall), treba zamijeniti nečim drugim, ali vam to sada nećemo otkriti, nego vam ostavljamo da na temelju prethodnih nastavaka serijala i vlastitog eksperimentiranja sami pronađe o čemu je riječ. U svakom slučaju preporučamo vam da sami probate „odraditi“ cijeli posao oko današnje aplikacije, kako bi mogli lakše pratiti slijedeći projekt, gdje ćemo još manje detaljizirati oko biranja kontrola i njihovog korištenja nego što je to bi slučaj danas. Budući da ćemo raditi na mnogo složenijem projektu jednostavno moramo pretpostaviti da su vam dobro poznate osnovne stvari oko korištenja Googleovog alata za neprogramere.
16. Korištenje kartografskih servisa U današnjem završnom nastavku svojevrsnog podserijala o korištenju Googleovog alata za brzo prototipiranje aplikacija, pokazat ćemo kako se u okviru tog alata koriste kartografske mogućnosti Googleovih servisa, jedne od najčešće korištenih tehnologija u aplikacijama na mobilnim uređajima. Dodatna vrlo zanimljiva razvojna tehnika demonstrirana u istom primjeru je pozivanje jedne Android aplikacije iz druge Android aplikacije. Već smo nekoliko puta spomenuli kako je trenutno jedno od najvećih ograničenja Googleovog razvojnog alata za neprogramere u tome što se unutar jedne aplikacije može koristiti samo jedan raspored kontrola. Upravo sposobnošću pozivanja jedne aplikacije iz druge može se zaobići spomenuto ograničenje. Način korištenja kartografskih servisa na kojem se temelji današnji tekst prikazan je u Googeovom primjeru pripremljenom od strane profesora Davida Wolbera sa sveučilišta u San Franciscu. Prije nego što nastavimo s detaljnijim objašnjavanjem primjera istaknimo na ovom mjestu još jednu bitnu mogućnost operativnog sustava Android u pogledu izrade rješenja koje se sastoji od većeg broja sastavnih dijelova. Dok za pozivanje drugog dijela aplikacije iz početnog dijela treba koristiti komponentu ActivityStarter, povratak unatrag se izvodi potpuno automatski. Dovoljno je samo izabrati standardnu operaciju operativnog sustava za tu namjenu, to jest odgovarajuću tipku na samom uređaju.
Prvi dio aplikacije (sučelje): Sastoji se od tri osnovne kontrole: Image1, ListPicker1 i ActivityStater1. U prvom dijelu aplikacije na osnovni zaslon projekta postavljene su svega tri kontrole: Image1, ListPicker1 i ActivityStater1. Kontrole su redom namijenjene za prikaz početne slike programa, izbor triju različitih odredišta za prikaz na karti, te na kraju komponente za pokretanje dodatne kartografski orijetirane aplikacije. Prve dvije kontrole ne bi trebale biti
posebno teške za korištenje, tako da ih nećemo ni posebno opisivati. Uostalom, kontrolu za prikaz slika koristili smo već u prvom, najtrivijalnijem primjeru korištenja alata. Nešto više vremena posvetit ćemo korištenju komponente ActivityStarter, zato što ona zahtijeva oblik znanja kakav je uobičajen u krugovima pravih Android programera, ali nije baš uobičajen za korisnike neprogramere. Drugim riječima, druga komponenta cjelokupnog rješenja mora se pozvati iz prve prema točnom definiranom protokolu, što bi u ovom slučaju imalo otprilike slijedeći oblik: ActivityStarter svojstvo Vrijednost Action android.intent.action.VIEW ActivityClass com.google.android.maps.MapsActivity ActivityPackage com.google.android.apps.maps
Prvi dio aplikacije (programski blokovi): Najvažniji dio povezan je aktivnostima kontrole ActivityStarter. Programski blokovi povezani s aplikacijom podijeljeni su u dva dijela. Prvi dio je zajedno s pratećim deklaracijama vrijednostima zadužen za pripremu početnog izgleda aplikacije (vidi prateću sliku uz tekst), dok se drugi izvodi nakon odabira neke od zadanih lokacija: “Tour Eiffel”, „Musee du Louvre“ i „Cathedrale Notre Dame“. Nakon odabira jednog od navedena tri mjesta iz popisa prelazi se na izvođenje programskog bloka ListPicker1.AfterPicking. Na ovom mjestu dolazimo do male dodatne komplikacija pa je treba objasniti nešto detaljnije. Da bi se pomoću komponente ActivityStarter mogla uspješno pokrenuti druga komponenta za prikaz nekog mjesta na mapi, potrebno je komponenti prenijeti adresu u točno propisanom formatu, a to
u ovom slučaju znači popunjavanje svojstva ActivityStater.DataUri. U spomenuto svojstvo mora se postaviti kombinacija vrijednosti „geo:0,0?q=“ te konkretne vrijednosti za izabranu lokaciju iz popisa dostupnih mjesta (ListPicker1.Selection). Za to se koristi posebni programski blok zadužen za rukovanje nizovima znakova (make text). U slučaju odabira druge od dostupnih vrijednosti dobije se konačna vrijednost: geo:0,0?q=’Musee du Louvre’.
Izvođenje aplikacije: Osnovni oblik izvođenja aplikacije u Android emulatoru. Sad je konačno sve spremno za pozivanje drugog dijela aplikacije, pa prvi dio aplikacije zaista predaje kontrolu izvođenja drugom dijelu na ranije opisani način. Po želji se (to smo isto već spomenuli) možete vratiti na prvi dio korištenjem standardne operacije u operativnom sustavu Android. „Sirovi“ oblik kartografskog prikaza kakav je u ovom trenutku prisutan u aplikaciji može se dalje nadograđivati tako da se modulu zaduženom za prikaz objekta mnogo preciznije zada način prikaza nekog mjesta prema sintaksi propisanoj od strane Googlea. Na primjer, za znatno atraktivniji način prikaza svih triju lokacija mogla bi se navesti „malo složenije odrednice“: Eiffel Tower http://maps.google.com/maps?f=q&source=s_q&hl=en&geocode=&q=eiffel+tower&sll=37.0625,‐ 95.677068 &sspn=48.909425,72.333984&ie=UTF8&hq=Tour+Eiffel&hnear=Tour+Eiffel,+Quai+Branly,+75007+ Paris,+Ile‐de‐France,+France&ll=48.857942,2.294748&spn=0.001249,0.002207&t=h&z=19 Musee Louvre
http://maps.google.com/maps?f=q&source=s_q&hl=en&q=louvre&sll=48.86096,2.335421&sspn= 0.002499,0.004415&ie=UTF8&t=h&split=1 &filter=0&rq=1&ev=zi&radius=0.12&hq=louvre&hnear=&ll=48.86096,2.335421&spn=0.002499,0. 004415&z=18 Notre Dame, Street View ttp://maps.google.com/maps?f=q&source=s_q&hl=en&q=french+landmarks&sll=48.853252,2.349 111&sspn=0.002411,0.004415 &ie=UTF8&t=h&radius=0.12&split=1&filter=0&rq=1&ev=zi&hq=french+landmarks&hnear=&ll=48. 853252,2.349111&spn=0,0.004415 &z=18&layer=c&cbll=48.853046,2.348861&panoid=74fLTqeYdgkPYj6KKLlqgQ&cbp=12,63.75,,0,‐ 35.58 U slučaju da želite provjeriti sami kako sve to skupa lijepo djeluje u praksi, a nemaze ni vremena ni volje da ispočetka razvijate cijelu aplikaciju, možete krenuti linijom manjeg otpora te usmjeriti svoj preglednik na adresu http://appinventor.googlelabs.com/learn/tutorials/maptour/maptour.html
Kontinuirani razvoj alata
Napredno izvođenje aplikacije: U prikaz su uključene dodatne opcije za prikaz slika na zadanoj lokaciji. U razdoblju od prvog spominjanja razvojnog alata App Inventor for Android u ovom serijalu, pa do današnjeg nastavka, Googleovi razvojni inženjeri marljivo su radili na njegovim unapređenjima (a rade i dalje). Budući da se razvoj aplikacija izvodi izravno u nekom od preglednika nije potrebno
preuzimati nikakve nove verzije alata da bi se iskoristile te novosti, nego su one odmah dostupne čim se alat slijedeći put pokrene nakon njegovog ažuriranja na Googleovom serveru. Osim ispravke uočenih pogrešaka prijavljenih od strane korisnika, izgleda da se najintenzivnije radi na daljnjim doradama komponenti u okviru kolekcije Other Stuff. Komponenta Web zamišljena je tako da osigurava dodatne mogućnosti u izravnom preuzimanju podataka s web servera, za što se do sada morao koristiti poseban Java kod (ili programski kod u nekom drugom programskom jeziku) distribuiran na server. Sada je postalo moguće pozivati određene skupine API funkcija izravno preko Web komponente. Na primjer, korištenjem poziva funkcija iz Yahoo Finance API biblioteke prilično je jednostavno u Android aplikaciju dodati prikaz različitih poslovnih informacija o čijoj pripremi i pouzdanosti brine Yahoo. Iako to nema izravne veze s temom današnjeg teksta, za eventualno zainteresirane ipak spomenimo kako se sve potrebne informacije o korištenju Yahoo Finance API tehnologije nalaze na adresi:http://www.gummy‐stuff.org/Yahoo‐data.htm
Web komponenta u akciji: Izravno korištenje Yahoo Finance API tehnologije. Za sada toliko o ovoj temi. Nadamo se da vas je sve do sada napisano potaklo da počnete razmišljati o razvoju vlastitih Android aplikacija, čak i ako niste programer, ili ako to nikada niste ni mislili postati. Kad savladate razvojni alat za neprogramere možda ćete poželjeti da se u budućnosti počnete baviti i „pravim“ Google Android programiranjem. Na njega ćemo se ponovo vratiti u slijedećem nastavku, kako bi pokazali još nekoliko naprednijih tehnika korištenja osnovnog SDK alata.
17. Što je novo u 3.x izdanjima Da čovjek jednostavno ne povjeruje kako vrijeme brzo leti – od početka serijala o programiranju korištenjem Googleovog razvojnog alata Android SDK, već je prošlo više od godinu dana, a u međuvremenu se je mnogo toga dobrog dogodilo sa samim alatom u smislu proširenja njegovih mogućnosti. Za to je prije svega zaslužna prava eksplozija pojave novih modela tablet računala, jer je upravo ona dovela do potrebe optimiziranja Android sustava za takvu vrstu hardvera.
Novosti u alatu App Inventor for Android Prije nego se pozabavimo osnovnim Android SDK razvojnim sustavom namijenjenom „pravim programerima“, napišimo nekoliko dodatnih riječi o najnovijim vijestima povezanim s Googleovim alternativnim alatom za brzo prototipiranje aplikacija (App Inventor for Android), jer smo se upravo njime bavili zadnjih nekoliko brojeva. Ako vam se alat dopao, pa zato planirate njegovo dugoročnije korištenje, važno je znati što vam očekuje u budućnosti. Prvo, i trenutno najvažnije, kao novu web adresa za online korištenje alata App Inventor for Android trebati će ubuduće koristiti www.appinventorbeta.com umjesto dosadašnje adrese appinventor.googlelabs.com. U duhu vođenja brige za postojeće korisnike vlastitih proizvoda, uobičajenom kod velikih IT poduzeća, sve postojeće aplikacije registriranih korisnika sačuvane su i dostupne na novoj adresi, tako da nema potreba za nekakvim „prepisivanjem“ aplikacija s jedne adrese na drugo.
Android 3.x: Donosi brojne promjene u korisničkom sučelju optimizirane za moderne tablet uređaje.
Drugo, te jednako važno za buduće korištenje alata, Google prestaje s izravnim radom na održavanju i razvoju alata App Inventor for Android. To na sreću ne znači da će alat nestati, nego da on prelazi u „open source“ kategoriju. Za budući status alata brigu će voditi novoosnovani Center for Mobile Learning u okviru MIT Media Laba, te biti pod stalnim nadzorom tri profesora s istog sveučilišta: Hal Abelson, Eric Klopfer i Mitchel Resnik. Prva osoba iz nabrojene trojke zaslužna je za predlaganje i pokretanje čitavog projekta 2008 godine zajedno s poduzećem Google, iz laboratorija drugog profesora potekla je prva verzija razvojnog alata, i to upravo na temelju ideje zadnjeg imena s popisa. Dovršetak cijelog postupka očekuje se do kraja godine, a postojeći korisnici alata će redovito dobijati informacije o svim promjenama.
Novosti u „osnovnom“ Android sustavu Nakon razjašnjavanja trenutne i buduće situacije s alatom za brzo prototipiranje Android aplikacija, vratimo se sada na osnovni razvojni alat Android SDK. Od trenutka početka pisanja serijala, kojeg upravo čitate, razvojni alat je promijenio svoju prvu brojčanu oznaku verzije s 2 na 3, što uvijek znači da je došlo do bitnih promjena u nekom softverskom paketu. Kao što smo to već spomenuli na samom početku ovog teksta, ključni okidač za takve promjene je sveopća „zaluđenost“ tablet računalima, kako od strane proizvođača, tako i od strane korisnika mobilnih uređaja. Budući da se po dijelu svojih hardverskih karakteristika takvi uređaji razlikuju od mobilnih telefona, Android sustav doživio je bitne promjene što simbolizira nova početna oznaka verzije. Pogledajmo prvo što se najvažnijeg dogodilo sa stanovišta krajnjeg korisnika. Najvažnije su, naravno, promjene na dimenzijama i rezoluciji zaslona, jer su ove vrijednosti u pravilu dosta veće nego kod mobilnih telefona. Povećanje zaslona pretpostavka je za dodatnu zabavu u korisničkom sučelju, kako u pogledu redizajna postojećih dijelova, tako i u pogledu dodavanja potpuno novih dijelova sučelja poput sistemske ili akcijske trake. Kad govorimo o promjenama u korisničkom sučelju onda se to odnosi na dio vidljiv na zaslonu, ali i na sistemske, grafički orijentirane module u pozadin,i koji su također morali doživjeti brojne promjene. Na većem zaslonu uređaja mogla se između ostalog redizajnirati softverska tipkovnica namijenjena unosu znakova. Tipkovnica je jednostavno postala udobnija te brža za korištenje nego prije, jer se do dijela tipki više ne mora dolaziti zaobilazno. Još jedna bitna stvar povezana s korisničkim sučeljem je poboljšana mogućnost upravljanja operacijama označavanja, isijecanja, kopiranja i umetanja teksta. Sada se za tu operaciju koriste dodatne strelice prikazane na zaslonu.
Promjene u poznatim aplikacijama: Na primjer, aplikacija za upravljanje ugrađenom kamerom. Prva od prije spomenutih traka, smještena na samom dnu zaslona, namijenjena je za brzi pristup obavijestima, statusnim pokazateljima sustava te navigacijskim gumbima postavljenim na sam zaslon. U pravilu sistemska traka dostupna je stalno, iako se ako je to baš potrebno može sakriti u slučaju da neka aplikacija treba iskoristiti cijeli dostupni prostor zaslona. Još jedan važan zadatak sistemske trake je upravljanje višezadatkovnim radom preko popisa nedavno korištenih aplikacija (Recent Apps). Druga traka (akcijska) nalazi se na vrhu zaslona, a izgled i djelovanje ovise joj o kontekstu izvođenja aplikacije, što znači da promjenom njezinog izgleda upravlja aplikacija, a ne sam Android sustav. Od ostalih novosti svakako treba spomenuti nove mogućnosti povezivanja tablet računala s vanjskim uređajima pomoću Media/Picture Transfer Protocola, odnosno povezivanje prave tipkovnice s uređajem kako bi se još više olakšalo upisivanje teksta. Na kraju tu je i nekoliko poboljšanja standardnih aplikacija – preglednik, elektronička pošta, kamera, galerija i imenik. U još novijim verzijama nasljednicama s oznaka 3.1 i 3.2 uvedena su dodatna unapređenja u korisničkom sučelju te povezivanju s vanjskim uređajima (npr. različiti dodaci za igru) i Wi‐Fi, dok je sam Android sustav optimiziran za brojne tablet uređaje, koji su se na tržištu pojavili u međuvremenu. U ovom nabrajanju ne smijemo nikako zaboraviti na još jednu promjenu, budući da ona nije vidljiva na prvi pogled, ali pridonosi ukupnom zadovoljstvu korištenja Android platforme. Osim što u verziji 3.x Android podržava istovremeno korištenje većeg broja aplikacija, sada se te aplikacije mogu izvoditi i na većem broju procesora odnosno jezgri, ako je takva hardverska konfiguracija ugrađena u mobilni uređaj. Android uređaji tako će uskoro moći rješavati najsloženije probleme, a da ne spominjemo kako će dobro na njima izgledati različite igre. U međuvremenu su se na tržištu zaista pojavili višejezgreni uređaji, tako da ovo više nije samo teoretska mogućnost sustava. Sad kad smo ukratko naveli što je sve novo u sustavu sa stanovišta krajnjeg korisnika, pogledajmo što to zapravo znači za programere, ako žele pisati optimizirane aplikacije za nove verzije Andrioda s početnom verzijom 3. Svaka nova verzija Androida sa sobom donosi izmijenjeno programsko sučelje s određenim brojem novih poziva API funkcija, odnosno izmjene u načinu korištenja postojećih funkcija. Budući da su se u verziji 3.0 (i novijima) pojavili potpuno novi dijelovi korisničkog sučelja, kao što je akcijska traka ili sistemska traka, najvažnije API promjene povezane su upravo s tim dijelovima. Drugim riječima, dobili smo sasvim dovoljno građe za još nekoliko nastavaka serijala u kojima bi se demonstrirale najnovije mogućnosti platforme. Navedimo sada primjer dijela programskog koda namijenje korištenju akcijske trake u vlastitim aplikacijama, tek toliko da steknete dojam kako to izgleda Detaljnije djelovanje programskog koda koji upravlja alatnom trakom, ali i drugim novostima verzije 3.x objasnit ćemo na složenijem primjeru kojeg počinjemo izrađivati slijedeći put. package com.example.android.apis.app; import com.example.android.apis.R; import android.app.ActionBar; import android.app.ActionBar.Tab; import android.app.Activity;
import android.app.Fragment; import android.app.FragmentTransaction; import android.os.Bundle; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.TextView; import android.widget.Toast; public class ActionBarTabs extends Activity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.action_bar_tabs); } public void onAddTab(View v) { final ActionBar bar = getActionBar(); final int tabCount = bar.getTabCount(); final String text = “Tab ” + tabCount; bar.addTab(bar.newTab() .setText(text) .setTabListener(new TabListener(new TabContentFragment(text)))); } public void onRemoveTab(View v) { final ActionBar bar = getActionBar(); bar.removeTabAt(bar.getTabCount() – 1);
} public void onToggleTabs(View v) { final ActionBar bar = getActionBar(); if (bar.getNavigationMode() == ActionBar.NAVIGATION_MODE_TABS) { bar.setNavigationMode(ActionBar.NAVIGATION_MODE_STANDARD); bar.setDisplayOptions(ActionBar.DISPLAY_SHOW_TITLE, ActionBar.DISPLAY_SHOW_TITLE); } else { bar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS); bar.setDisplayOptions(0, ActionBar.DISPLAY_SHOW_TITLE); } } public void onRemoveAllTabs(View v) { getActionBar().removeAllTabs(); } private class TabListener implements ActionBar.TabListener { private TabContentFragment mFragment; public TabListener(TabContentFragment fragment) { mFragment = fragment; } public void onTabSelected(Tab tab, FragmentTransaction ft) { ft.add(R.id.fragment_content, mFragment, mFragment.getText()); } public void onTabUnselected(Tab tab, FragmentTransaction ft) { ft.remove(mFragment); }
public void onTabReselected(Tab tab, FragmentTransaction ft) { Toast.makeText(ActionBarTabs.this, “Reselected!”, Toast.LENGTH_SHORT).show(); } } private class TabContentFragment extends Fragment { private String mText; public TabContentFragment(String text) { mText = text; } public String getText() { return mText; } @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { View fragView = inflater.inflate(R.layout.action_bar_tab_content, container, false); TextView text = (TextView) fragView.findViewById(R.id.text); text.setText(mText); return fragView; } } }
View more...
Comments