Lociranje in mreženje z Androidom
V predhodnjem članku smo predstavili kako lahko v programski kodi dostopamo do kamere, z njo zajamemo sliko in jo predelamo z lastnimi filtri. V nadaljevanju bomo že razvito aplikacijo nadgradili tako, da bo naprava v trenutku zajema slike zajela tudi položaj, kjer je bila fotografija narejena, jo predelala kot smo predstavili v predhodnjem članku, nato pa jo bo preko spleta naložila na spletno storitev "Kje kaj dogaja?", razvito posebej za demonstracijo delovanja aplikacije. Vsebina članka je skupaj s programsko kodo, kot v preteklosti, dosegljiva na android.monitor.si. Storitev "Kje kaj dogaja?" je dosegljiva na spletnem naslovu android.monitor.si/kajdogaja.
Večina aplikacij potrebuje način za interakcijo, ki zahteva izbiro določenih akcij ali nastvljanje določenih opcij aplikacije. Ena izmed najpogostejših rešitev je uporaba menijev, predstavljena v nadaljevanju članka. Predstavili bomo kako lahko zgradimo tako statične, kot dinamične menije. Med tem, ko je prvi pristop uporaben v primeru nespremenljivih menijev, je drugi pristop primeren predvsem, kadar se meniji med izvajanjem aplikacije večkrat spreminjajo glede na stanje aplikacije. V članku bomo predstavili tudi načine uporabe v mobilne naprave vgrajene pripomočke za določanje naše lokacije in njihovo uporabo. Da bomo lahko sliko naložili na spletno storitev, pa bomo spoznali tudi načine kako uporabiti mrežno povezljivost za opravljanje takšnih nalog. Z omenjenimi funkcionalnostmi bomo nadgradili aplikacijo razvito v okviru prejšnjega članka.
Meniji
Najpogostejši pristop za izgradnjo interaktivnega uporabniškega vmesnika predstavlja uporaba menijev. Meniji lahko zavzemajo veliko različnih oblik, ki so za določena opravila bolj ali manj uporabni. V sistemu Android so ravno meniji pri prehodu iz različic 2.x v 3.0 doživeli veliko predelavo v obliki "akcijske vrstice". Pred različico 3.0 so bili meniji dosegljivi zgolj preko namenskega gumba na mobilni napravi. Od različice 3.0 meniji predstavljajo del uporabniškega vmesnika, ki je stalno prikazan na zaslonu (razen kadar ga uporabnik eksplicitno skrije). S tem pristopom uporabniški vmesnik seveda neprestano zavzema del zaslona, a po drugi strani odpade potreba po dodatnem gumbu na napravi. Kljub spremembi, je sistem še vedno zasnovan tako, da podpira združljivost za nazaj in kadar različica sistema ne podpira prenovljenih menijev, le-te prikaže v obliki, primerni za uporabljeno različico sistema. Menije v aplikaciji delimo na "akcijsko vrstico in opcijski meni", "kontekstni meni" in "pojavni meni".
Akcijska vrstica in opcijski meni
Akcijska vrstica, ki je v novejši različici sistema nadomestila opcijski meni, predstavlja osnovni gradnik namenjen navigaciji po različnih zaslonskih maskah aplikaicje. Akcijska vrstica v demonstracijski aplikaciji je prikazana v sliki 1. Akcijsko vrstico lahko definiramo v ustrezni datoteki XML in je prikazan v spodnjem primeru.
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="schemas.android.com/apk/res/android">
<item android:id="@+id/menu_save"
android:icon="@drawable/ic_menu_save"
android:title="@string/menu_save"
android:showAsAction="ifRoom|withText" />
</menu>
Postavka android:icon predstavlja ikono izbire v akcijski vrstici, android:title pa napis ustrezne izbire. S postavko android:showAsAction lahko določimo ali naj sistem sam izbere kako prikazati izbiro (ifRoom), vedno prikažemo izbiro v akcijski vrstici (always), prikažemo napis (withText), sestavljen prikaz (v zgornjem primeru), ali pa se izbira pojavi v opcijskem meniju (never). Priporočljivo je, da v akcijsko vrstico ne silimo preveč izbir (z opcijo always) ampak v vrstico prisilno dodamo samo najpomembnejše izbire, ostale pa prepustimo da jih sistem po potrebi prikaže v prelivnem meniju (angl. overflow menu).
SLIKA 1: Prikaz akcijske vrstice v aplikaciji s prelivnim menijem.
Zaradi združljivosti s starejšmi napravami na katerih so starejše različice sistema Android, se primer datoteke XML v takšnih primerih uporabi za izgradnjo opcijskih menijev, ki se pojavijo ob pritisku na gumb "menu". Primer aplikacije, ki uporablja opcijske menije je prikazan na sliki 2, kjer so vse izbire prikazane v opcijskem meniju.
SLIKA 2: Prikaz opcijskega menija v aplikaciji.
Naši aplikaciji bomo v akcijsko vrstico dodali gumbe "Slikaj!", "Uredi uporabnika", "Dodaj metapodatke" in "O aplikaciji", ki bodo namenjeni za interakcijo z aplikacijo in urejanje nastavitev. Strukturo menijev definiramo v datoteki XML na podoben način, kot je prikazano v primeru z razliko, da definiramo več menijskih izbir ki jih določimo z značkami item.
V našem primeru smo uporabili zgolj osnovno funkcionalnost akcijske vrstice, ki poleg omenjenega ponuja še širok nabor ostalih funkcionalnosti. Tako lahko uporabimo deljeno akcijsko vrstico, ki se pojavi hkrati na zgornjem in spodnjem delu zaslona kamor se porazdelijo možne akcije. Razdeljena akcijska vrstica se največkrat uporabi takrat, ko ima naprava ozek podolgovat zaslon (mobilni telefon).
Kontekstni meni
Kontekstni meni je namenjen urejanju določenega objekta uporabniškega vmesnika ali izvedbe določene akcije nad nekim elementom (urejanje, brisanje, kopiranje, ...). Tako kot je akcijska vrstica nadomestila opcijski meni, je bil v različicah sistema, novejših od 3.0, v sistem Android vpeljan tudi nadomestni koncept za kontekstni meni, imenovan kontekstni akcijski način, kjer se akcije namesto v kontekstnem meniju pojavijo v vrstici pod akcijsko vrstico. Oba pristopa sta predstavljena v sliki 3. Naša aplikacija zaradi preprostosti ne potrebuje in zato ne vsebuje primerov kontekstnega menija ali kontekstnega akcijskega načina.
SLIKA 3: Prikaz razlike med kontekstnim menijem in kontekstnim akcijskim načinom (vir: developer.google.com)
Pojavni meni
Pojavni meni (angl. popup menu) je vezan na posamezni primerek razreda Viev, ki predstavlja osnovno enoto uporabniškega vmesnika. Pojavni meniji so uporabni kadar želimo na nek del uporabniškega menija (gumb, ali kakšno drugo kontrolo) vezati več povezanih sekundarnih akcij (primer takšne kontrole je lahko gumb "Dodaj", kjer se v pojavnem meniju pojavijo možne opcije dodajanja, ali na primer gumb "Deli", kjer se v pojavnem meniju pojavijo možnosti oz. načini deljenja vsebine: elektronska pošta, brezžična povezava, MMS, ...). Slika 4 prikazuje primer pojavnega menija v sistemu priloženi aplikaciji Gmail. Zaradi preprostosti implementacije naša aplikacija ne vsebuje primera uporabe pojavnih menijev.
SLIKA 4: Prikaz pojevnega menija v osnovni aplikaciji Gmail, ki je priložena k sistemu.
Lokacija
V prejšnjem članku smo predstavili kako lahko razvijalci dostopamo do kamere mobilne naprave. Poleg kamere, včasih tudi več kot ene, imajo sodobne mobilne naprave na voljo še vrsto ostale strojne opreme, ki jo lahko izkoristimo. V nadaljevanju bomo predstavili, kako lahko od sistema pridobimo trenutno oz. zadnjo znano lokacijo naprave.
Sistem uporabniku ponuja dostop do informacij o lokaciji preko sistemske storitve lokacijskega upravljalca, ki ga predstavlja razred LocationManager. Preko omenjenega razreda, katerega primerek lahko dobimo zgolj od sistema samega s klicem metode getSystemService(Context.LOCATION_SERVICE) lahko pridobimo seznam vseh ponudnikov lokacije, ki lokacijo pridobijo iz različnih virov, kot so brezžična dostopna točka, dostopna točka mobilnega omrežja ali pa namenski GPS modul, ki ponuja najbolj natančno določeno lokacijo.
Da aplikacije sploh smejo uporabljati lokacijske podatke pridobljene s strani sistema, moramo podobno kot za uporabo kamere aplikaciji dodeliti ustrezna dovoljenja. V primeru uporabe lokacijskih ponudnikov je to naslednje dovoljenje:
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
ki ga je potrebno dodati v Manifest datoteko naše aplikacije.
V naši aplikaciji smo zadnjo znano lokacijo pridobili od prvega ponudnika s seznama vseh, ki so na razpolago. Pri tem nismo preverjali ali je ponudnik lokacije v trenutku pridobivanja vklopljen ali ne. Vklop in izklop pridobivanja lokacije prepuščamo uporabniku samemu. V večini primerov je seveda priporočljivo aplikacijo izdelati tako, da uporabnika opozori, kadar želi dostopati do lokacijskih storitev pa so te izključene. To je še posebej priporočljivo takrat, ko je zelo pomembno, da je lokacija čim bolj natančna in ažurna, na primer pri sprotnem spremljanju uporabnika. V nadaljevanju je prikazan del kode, ki prikazuje, kako pridobimo zadnjo znano zemljepisno širino in dolžino:
double lat = 0; // spremenljivka za hranjenje zemljepisne širine
double lon = 0;// spremenljivka za hranjenje zemljepisne dolžine
LocationManager locationManager =
(LocationManager) getSystemService(LOCATION_SERVICE);
List<String> providers=locationManager.getProviders(true);
if (providers.size()>0) {// ali ponudnik lokacije sploh obstaja
Location location =
locationManager.getLastKnownLocation(providers.get(0));
lat=location.getLatitude();
lon=location.getLongitude();
} else {
lat = Double.MIN_VALUE;
lon = Double.MIN_VALUE;
}
V kolikor v zgornjem primeru ugotovimo, da mobilna naprava nima nobenega ponudnika lokacije, to je v primeru ko je seznam ponudnikov prazen, postavimo vrednosti zemljepisne širine in dolžine na minimalno vrednost tipa double. To seveda ni povsem regularna rešitev, saj se lahko naprava v primeru nepravilnega delovanja vrne tudi takšne vrednosti.
Mreženje
Mrežna povezljivost predstavlja pomembno funkcionalnost današnjih mobilnih naprav. Veliko aplikacij prav s povezavo v internet dobi pravo funkcionalnost, nekatere pa brez povezave sploh ne delujejo. Velikokrat je cilj aplikacij deljenje informacij s prijatelji na različne načine, največkrat preko socialnih omrežij. Za potrebe članka smo tako pripravili preprosto demonstracijsko spletno storitev namenjenu deljenju fotografij z dodatnimi informacijami o geolokaciji fotografije, imenom avtorja in kratkim opisom dogajanja, prikazanega na sliki. Spletna storitev je na voljo na spletnem naslovu android.monitor.si/kajdogaja/. Spletna storitev je lahko realizirana v poljubni spletni tehnologiji, v našem primeru v programskem jeziku PHP.
Podobno kot postopamo pri ostalih virih platforme Android (lokacijske storitve, kamere, ... ), velja tudi za mrežne storitve. Omrežno povezljivost lahko mobilna naprava vzpostavi na več načinov, najpogosteje preko mobilnega omrežja ali preko brezžične povezave. Kdaj se uporablja kateri izmed načinov določa sistem sam. Prioriteto daje brezžični povezavi, saj je ta način za uporabnika cenejši. V primeru, ko brezžična povezava ne obstaja ali je izključena sistem avtomatsko preklopi na uporabo mobilnega omrežja v kolikor je ta seveda na razpolago.
Za razliko od pridobivanja lokacije nam v primeru mrežne povezljivosti ni potrebno ročno preverjati ali obstaja kakšen ponudnik mrežne povezljivosti. Za to v tem primeru poskrbi sistem sam. Na razvijalcu je na naloga, da sam preveri ali omrežna povezava obstaja in v primeru, ko ne obstaja, o tem obvesti uporabnika.
Na tem mestu naj omenimo, da je enako kot za veliko ostalih storitev, tudi za storitev uporabe interneta potrebno aplikaciji dodeliti ustrezno dovoljenje. Dovoljenje je potrebno dodati v manifest datoteko kot je prikazano spodaj.
<uses-permission android:name="android.permission.INTERNET" />
V našem primeru smo za pošiljanje slike na spletno storitev uporabili preprosto zahtevo "HTTP Post". Za potrebe pošiljanja smo za kodiranje podatkov uporabili priročno knjižnico "base64", ki podatke zakodira tako, da jih na strani spletne storitve brez problemov dekodiramo. Knjižnica, ki smo jo uporabili je dostopna na spletnem naslovu iharder.sourceforge.net/current/java/base64/, in jo brez problema uporabimo tudi pri razvoju Android aplikacij.
Fotografijo, ki jo pošiljamo na spletno storitev najprej zakodiramo s prej omenjeno metodo, kar je prikazano v spodnjem primeru:
ByteArrayOutputStream bao = new ByteArrayOutputStream();
bmp.compress(Bitmap.CompressFormat.JPEG, 75, bao);
byte [] ba = bao.toByteArray();
String ba1= fri.lgm.tmp.Base64.encodeBytes(ba);
Vse podatke na spletno storitev naložimo s pomočjo razreda HttpClient, ki je del Android pakera API. Za potrebe pošiljanja vse podatke pripravimo v obliki parov <ključ, podatki>, kar naredimo s preprostim seznamom, ki vsebuje takšne objekte. Primer izdelave takšnega seznama je prikazan v spodnjem primeru:
ArrayList<NameValuePair> nameValuePairs = new ArrayList<NameValuePair>();
nameValuePairs.add(new BasicNameValuePair("image",ba1));
nameValuePairs.add(new BasicNameValuePair("gpsX", ""+lat));
nameValuePairs.add(new BasicNameValuePair("gpsY", ""+lon));
nameValuePairs.add(new BasicNameValuePair("comment", comment));
nameValuePairs.add(new BasicNameValuePair("user", username));
Ko imamo pripravljene vse podatke, ki jih želimo poslati na spletno storitev ustvarimo nov primerek razreda HttpClient, zanj kreiramo primerek post zahteve, za določen URL naslov, ki ji pripnemo predhodno sestavljen seznam parov. Nadalje zahtevo s pomočjo spletnega klienta posredujemo na strežnik. Opisan postopek je predstavljen v spodnjem primeru
HttpClient httpclient = new DefaultHttpClient();
HttpPost httppost =
new HttpPost("<URL naslov strežnika>");
httppost.setEntity(new UrlEncodedFormEntity(nameValuePairs));
HttpResponse response = httpclient.execute(httppost);
HttpEntity entity = response.getEntity();
API od nas zahteva, da zahtevo na strežnik pošiljamo v niti, ki je ločena od osnovne niti grafičnega uporabniškega vmesnika. Bolj veščim uporabnikom je koncept večnitnih programov dobro znan. V primeru potrebe po uporabi večih jeder, ki so na voljo v napravi, lahko slednja izkoristimo z dodatnimi nitmi. Te niti se načeloma izvajajo medsebojno neusklajeno. Podatke, ki jih v ločenih nitih izračunavamo, moramo dobro sinhronizirati, saj lahko v nasprotnem primeru program daje nepričakovane rezultate. V primeru pošiljanja zahteve pa je nova nit uvedena zaradi uporabniške izkušnje. V kolikor bi zahtevo pošiljali v osnovni niti in bi pri vzpostavljanju povezave prišlo do zapletov (npr. počasna povezava), bi uporabniški vmesnik za določen čas postal neodziven. Nit, ki bi skrbela za izris, bi bila obremenjena pošiljanjem zahteve do te mere, da ne bi več skrbela za osveževanje vmesnika glede na uporabnikovo interakcijo. Ker si takšnega obnašanja aplikacije ne želimo, ločimo pošiljanje v svojo nit. Za slednjo nas niti ne skrbi, v kolikšnem času bo dokončala svoje opravilo, saj nas trajanje opravila ne omejuje več pri osveževanju uporabniškega vmesnika.
Ko zahtevo pošljemo na strežnik dobimo od slednjega odgovor o uspešno ali neuspešno izvedeni zahtevi in o tem ali so bili podatki uspešno naloženi in obdelani. Ta odziv v naši aplikaciji uporabimo, da uporabnika obvestimo o uspešnosti izvedene akcije preko pojavnega obvestila, ki se v sistemu Android imenuje toast. Primer pikaza obvestila toast je prikazan v sliki 5.
SLIKA 5: Primer prikaza obvestila toast.
Spletna storitev
V nadaljevanju bomo na kratko predstavili spletno storitev "Kje kaj dogaja?", ki je v članku večkrat omenjena. Spletna storitev, ketere uporabniški del je prikazan na sliki 6, od Android aplikacije preko zahteve post prejme podatke, ki vključujejo sliko, ime uporabnika in kratek opis. Uporabnik mora biti za uporabo storitve registriran. Zaradi varnosti se preverja ali so naloženi podatki res v ustrezni obliki (ali je slika res slika), in ali ne presegajo določene velikosti. V primeru, da naloženi podatki ne ustrezajo predpisanim zahtevam, storitev zavrne naložene podatke in uporabniku sporoči do kakšne napake je prišlo (ali uporabnik ni registriran, ali je datoteka prevelika, ali datoteka ni slika). Napake se enako kot obvestilo o uspešno naloženi sliki uporabniku posredujejo preko obvestila. Pri implementaciji smo uporabili ogrodje za prikaz spletnih zemljevidov Bing, na katerih prikažemo geolocirane fotografije, ki jih nalagajo posamezni uporabniki. Spletna storitev je omejena na prikaz zadnjih stotih naloženih fotografij, da na zemljevidu preprečimo "poplavo" prikazanih fotografij.
V kolikor želite pokukati tudi v izvorno kodo spletne storitve kontaktirajte katerega izmed avtorjev članka preko elektronske pošte.
SLIKA 6: Prikaz spletne storitve "Kje kaj dogaja?", nemenjene demonstraciji uporabljenih funkcionalnosti platforme Android.
Povzemimo
Članek predstavlja hiter pregled funkcionalnosti lociranja uporabnika in mrežnega povezovanja s pomočjo mobilne naprave s platformo Android. Aplikacijo razvito v okviru predhodnjega članka, namenjeno fotografiranju in adaptaciji fotografij s filtri smo razširili v več korakih. V prvem koraku smo v aplikacijo vpeljali pridobivanje lokacije z uporabo namenkega razreda, ki je del paketa Android API. V naslednjem koraku smo dodali mrežno povezljivost, pri čemer smo za preprostejši prenos slik uporabili priročno knjižnico za kodiranje, Z uporabo podpornih razredov, ki so del platforme smo podatke poslali na spletni storitev in od nje pridobili odziv, ki ga prikažemo uporabniku.
V članku so predstavljeni zelo osnovni pristopi, zato priporočamo, da upoštevate priporočila, kako takšne osnovne pristope razširiti za primernejšo uporabo v končnih aplikacijah, ki jih boste objavljali za končne uporabnike. Tako kot v predhodnjih člankih, bo koda Android aplikacije objavljena na spletnem naslovu android.monitor.si.
Za namene prikaza uporabe lokacijskih storitev in mrežne povezljivosti smo postavili namensko spletno storitev, ki na zemljevidu prikazuje geolocirane fotografije. S klikom na posamezno prikazano fotografijo se prikaže večja fotografija s kratkim opisom in imenom avtorja.
Pridobivanje lokacije uporabnika lahko na platformi Android pridobimo iz različnih virov. Lokacijo lahko pridobimo od samega ponudnika mobilne telefonije glede na bazno postajo, natančnejšo lokacijo lahko pridobimo preko dostopne točke za brezžično omrežje, za še natančnejšo lociranje pa lahko uporabimo GPS modul, ki ga prav tako vsebuje velika večina današnjih mobilnih naprav.
Dostop do interneta je mogoč na več načinov; preko brezžičnega omrežja v kolikor je to na razpolago in je na napravi omogočeno ali preko mobilnega omrežja, če je na voljo paketni prenos in je prenos omogočen.