Online Android szakkör (DKRMG)
Ebben a leckében végre ismét egy olyan programot készítünk, ami kevés kóddal is látványos eredményt ér el! A célunk egy térkép megjelenítése az androidos okostelefonunk kijelzőjén, ami gombnyomásra tetszőleges helyre ugrik.
Joggal kérdezhetnénk: hány száz sor kódot kell megírnunk ahhoz, hogy egy olyan térképet jelenítsünk meg, ami a világ bármely pontjára elrepít minket, követve az ismert ujj mozdulatokat (mozgatás, nagyítás)? Pedig nem lesz szükségünk másra, mint pár layout elemre, és körülbelül tíz sor új Java kódra.
A programozás hőskorában nem ment ritkaságszámba az, hogy minden fejlesztő (vagy cég) a legapróbb problémák megoldására is saját kódrészletek írásába kezdett. A Java nyelv kellő ismeretével mi is megtehetnénk ezt, ám kérdés, hogy miért vesztegetnénk az időnket és erőnket már rég megoldott feladatokra. Kissé közhelyesen: ne akarjuk újra feltalálni a spanyolviaszt! Rengeteg népszerű programozási problémára léteznek szabadon elérhető, nyilvános és sokszor ingyenes kódcsomagok, amikhez a fejlesztőjük (vagy fejlesztőcsoportjuk) úgynevezett API-kon keresztül hozzáférést biztosít számunkra.
A helyzet talán nem is teljesen ismeretlen számunkra. Az Android beépített függvénytára már most is rengeteg munkát vesz le a vállunkról (ablakok kirajzolása, Activityk megnyitása, kezelése, szenzorok használata stb.). Ezúttal egy újabb nyilvános API-val ismerkedünk meg, amely kifejezetten térképek megjelenítésére alkalmas.
Több ingyenesen elérhető térkép API is elérhető jelenleg az interneten. Az Open Street Map projekt egy közösségalapú térkép. Az adatokat magánemberek szolgáltatják, akár Te is hozzáadhatsz új elemeket! A projekthez kapcsolódó osmdroid pedig a világtérképet elérhetővé teszi az Android kódunkból is. A Google Maps is nyújt hasonló API-t, azonban ennek használatát a Google szigorúbb ellenőrzés alatt tartja. A Google Maps API első használata előtt be kell szereznünk egy Android Certificate-t és egy Google Maps API keyt. Ezek ugyan ingyenesen elérhetőek, ebben a leckében most úgy döntöttünk, hogy megkíméljük az olvasót ettől a kényelmetlenségtől, és a könnyebb utat választva inkább az Open Street Map térképeit használjuk. Az érdeklődők itt megnézhetik a Google Maps használatát is, az sem ördöngősség...
Fontos megjegyezni, hogy ennek a leckének a sikeres teljesítéséhez (illetve az elkészült program használatához) szükség lesz a telefonon internetelérésre. A program működik mobilneten keresztül is, de nagyon változó, hogy éppen mennyi adatot szeretne letölteni, ami lehet sok, így drága is. Ezért azt javasoljuk, hogy mindenképp az otthoni WiFi-re legyetek felcsatlakozva, miközben használjátok a programot! Reméljük ez nem okoz gondot senkinek.
Az Open Street Map használatához először is szükségünk van egy új alkalmazásra. Ezt hozzuk létre most a szokásos módon. Remélhetőleg ez már mindenkinek kisujjból megy, de ha esetleg mégsem (régen volt rá utoljára szükség), akkor pl. a 7. lecke leírásából lehet puskázni.
Ha kész az új projektünk, akkor nyissuk meg a build.gradle
fájlunkat.
Ez a fájl mondja meg az Android Studio-nak, hogy miként fordítsa le a programunkat. Épp
az imént itt módosítottuk például, hogy milyen SDK-val rendelkező telefonokat
támogassunk. Most azonban a figyelmünket fordítsuk inkább a dependecies
rész felé.
A gradle fájl dependencies
részlete tartalmazza azon kódcsomagok listáját, amik nem
részei se az Android rendszernek, se a Java nyelvnek. A lista már most sem feltétlenül üres,
az Android Studio esetenként például már hozzáadta az appcompat könyvtárat. Ha a te dependencies listád
más elemeket tartalmaz mint a képen láthatóak, akkor sem kell aggódnod. A lényeg az, hogy
a lista végére oda kerüljenek az Open Street Map könyvtárai, ezáltal jelezve az Android Studio-nak,
hogy mostantól tekintsen úgy a térkép API-ra, mint bármilyen más belső kódra.
Ehhez másoljuk be az alábbi két sort a dependencies blokk végére:
compile 'org.slf4j:slf4j-android:1.6.1-RC1'
compile 'org.osmdroid:osmdroid-android:4.3'
Most pedig kattintsunk a sarokban felugró Sync now
feliratra!
Ha valami oknál fogva a Sync now
sáv nem ugrik fel magától, akkor sem történik
semmi probléma. A gradle fájl változtatása után nyojuk meg a fenti sávban található
Sync Project with Gradle Files
gombot (lenti képen pirossal keretezve).
Korábban a rezgőmotor használatakor is láthattuk már, hogy az Android rendszer bizonyos hardverelemek használatát külön engedélyhez köti. Emlékeztetőként nézd meg a gyorssegély lapot!
Az alkalmazásunk a szükséges engedélyek listáját az AndroidManifest.xml
fájlban tárolja.
Nyissuk meg a manifeszt fájlt
Adjuk hozzá az OSM projekt által ajánlott engedélyeket az application
sor fölé
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE"/>
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
A fenti engedélyek listája az OSM honlapjáról származik, és közülük néhányra a mi
alkalmazásunknak szigorúan véve nem lesz szüksége (pl. FINE_LOCATION
). Az
Android programozás világában sajnos elfogadott szokás ilyenkor is kikérni az engedélyt
amolyan "ártani nem árt" alapon. Azonban komolyabb alkalmazások készítésekor
javasolnánk, hogy igyekezz a lehető legkevesebb engedélyre szorítkozni.
A térkép megjelenítésére egy ún. MapView típusú komponenst fogunk használni. Hiába
nézegetjük azonban a baloldali palettát, ott a szokásos komponenseinken
(Button
, TextView
, EditText
,
ListView
) túl nem találunk semmi újat. A Layout szerkesztő a külső
kiegészítő komponenseket a Custom
pont alatt rejti el.
Kattintsunk A Custom
pont alatt a CustomView
-ra.
A felbukkanó ablak kiegészítő komponensek egész hadát rejti. Itt válasszuk ki a
MapView (org.osmdroid.views)
komponenst, majd a layout szerkesztőben a telefonra
kattintva helyezzük el a képernyő közepén. A térkép helyén ilyenkor egy szürke
rácsos mintát látunk csak.
Előfordulhat, hogy elsőre a layout szerkesztő még panaszkodik az ismeretlennek tűnő komponens miatt
The following classes could not be found...
. A probléma megoldható a jobb felső sarokban található
frissítés gomb megnyomásával.
Ne felejtsük el a térkép id
tulajdonságát beállítani!
A felhasználói felület kialakításával már csak egy lépés maradt hátra a térkép megjelenítéséhez: az Activitynk indulásakor be kell állítanunk a térképünk pár fontos tulajdonságát.
Először is:
Hozzunk létre az Activity elején egy új MapView
típusú változót
(mondjuk terkep
néven)
Rendeljük hozzá a terkep
változóhoz a térkép komponensünket az onCreate
-ben
(findViewById
).
A térképünk tulajdonságait praktikus módon rögtön az onCreate
függvényben
be is állíthatjuk:
terkep.setTileSource(TileSourceFactory.MAPNIK); // térkép forrása
terkep.setBuiltInZoomControls(true); //nagyitás/kicsinyítés látszik
terkep.setMultiTouchControls(true); // kétujjas nagyítás/kicsinyítés engedélyezése
Igen! Indítsd el a programot, és ha pontosan követted a fenti leírást, egy csinos kis világtérképnek kell várnia a telefonod kijelzőjén.
Induláskor a térképünk jelenleg az egész földet mutatja kilapítva (esetenként több példányban egymás mellett). Manuálisan lehetőségünk van nagyítani és mozgatni a térképet, így megkeresve a számunkra épp érdekes részletet, ám mennyivel hasznosabb lenne, ha a térkép gombnyomásra egy általunk érdekesnek tartott helyre ugrana!
Az alábbi kód alkalmas ennek elérésére:
IMapController mapController = terkep.getController();
mapController.setZoom(17);
GeoPoint startPoint = new GeoPoint(47.632485, 19.131230);
mapController.setCenter(startPoint);
A térképen a pozíciót a földrajzi szélesség és hosszúság segítségével határozhatjuk meg
Azt szeretnénk elérni, hogy a felhasználói felületen legyen 5 gomb, ami mind más-más helyre repít el minket a térképen. Ehhez megtehetnénk, hogy a fenti kódot öt példányban bemásoljuk a gombjaink kattintását kezelő onClick függvényeibe. Másolgatás helyett azonban ezúttal inkább készítünk egy saját függvényt
A korábbi leckék során már sokszor emlegettük a függvényeket, de úgy igazán nem
néztük meg, hogy mik is azok pontosan. Ezt most pótolnánk. Ha úgy érzed, hogy
Te már ismered a függvények lelkivilágát, nyugodtan ugord át ezt a részt.
Természetesen bármikor vissztérhetsz.
Akik kevésbé magabiztosak a függvényeket illetően, vagy csak Javaul nem ismerik őket,
nekik érdemes átolvasni a kattintás után megjelenő kitérőt.
Most készítsünk egy új függvényt az Activitynkben, mondjuk navigalj
néven!
A navigalj
függvénynek két argumentum kell: a szélesség és a hosszúság,
ahová menni szeretnénk.
void navigalj(double szelesseg, double hosszusag) {
//...
}
A függvény törzsét neked kell befejezned a térkép mozgatására vonatkozó kód segítségével.
A layouthoz adj hozzá 5 gombot. Ha kell, méretezd át a térkép komponenst, és az alá/fölé
rakd le a gombokat. Ne felejtsük el id
tulajdonságokkal ellátni a gombokat
és a RelativeLayout gyökérelemet sem. Akik megcsinálták a
korábbi szorgalmit,
amiben a menükezelést mutattuk be, azt is használhatják, és úgy megmaradhat teljes
képernyősnek a térkép.
Most készíts minden gombnak egy onClick függvényt. Ehhez segítséget a gyorssegély lapon
találsz. Ezek a függvények pedig hívják meg a navigalj
függvényt az alábbi
paraméterekkel:
gomb: 47.632485, 19.131230
gomb: 47.496122, 19.039881
gomb: 51.500695, -0.124534
gomb: 40.783217, -73.966429
gomb: 48.858225, 2.294386
Futtasd az alkalmazást, és nézd meg, hogy melyik gomb hova visz a térképen! Ennek megfelelően írd át a gombok feliratát!
A mapController.setCenter(startPoint);
szemmel láthatóan áthelyezi a térkép
középpontját. A MapView osztály viszont tartalmaz egy másik függvényt is, ami ezt az ugrás-szerű
lépést kicsit finomabbá teszi.
mapController.animateTo(startPoint);
Írd át a programodat, hogy ezt az új függvényt használja a setCenter
helyett.
Milyen szerencse, hogy megírtuk a navigalj
függvényt, így csak egyetlen helyen változik
a program kódja (öt helyett).
Az elkészült műveket küldjétek el nekünk a feltöltő oldalon keresztül!