8 Maps Ένα πολύ σημαντικό κομμάτι πολλών εφαρμογών για κινητά, χρησιμοποιούν χάρτες και τη θέση του χρήστη για να πραγματοποιήσουν κάποιες λειτουργίες που δεν είναι δυνατόν να συμβούν με έναν απλό υπολογιστή. Σε αυτό το κεφάλαιο θα μάθετε κάποια βασικά πράγματα για να χρησιμοποιείτε χάρτες στις εφαρμογές σας. 8.1 Δημουργία Activity με χάρτη Δημιουργήστε μια νέα εφαρμογή (Project). Κατά την δημιουργία, καλό είναι να αποφύγετε το API 22 γιατί σε κάποιες εκδόσεις Android παρουσίαζε προβλήματα στον emulator (ίσως όμως δουλέψει και χωρίς κάποιο πρόβλημα στο δικό σας). Στη συνέχεια δημιουργήστε ένα Map Activity, κι όχι Plain όπως χρησιμοποιούσατε ως τώρα. Μανώλης Τσικνάκης, Αλέξανδρος Ρονιώτης, Ευαγγελία Μανιαδή Ηράκλειο 2016
Συνεχίσετε μέχρι να δημιουργήστε το Project σας και να ξεκινήσει στο περιβάλλον του Android Studio. 8.2 Google Maps API key Την πρώτη φορά που θα ανοίξει, θα σας ανοίξει το αρχείο google_maps_api.xml, στο οποίο θα πρέπει να εισάγετε στη θέση του YOUR_KEY_HERE το δικό σας Google Maps API Key, το οποίο θα βρείτε στο https://console.developers.google.com/flows/enableapi?apiid=maps_android_backend&keytype =CLIENT_SIDE_ANDROID&r=30:1A:F2:B1:83:57:1C:99:7A:BA:0C:C2:50:4F:96:E1:96:6A:9A:51%3Bgr.digiex plore.mymapsapplication Στη συνέχεια πατήσετε Create Project και Continue Στη συνέχεια επιλέγουμε Create API Key Σελίδα 2
Λογικά στο τέλος, αν όλα πάνε καλά, θα σας εμφανιστεί το API Key που θα χρησιμοποιήσετε για να αντικαταστήσετε το στοιχειο με όνομα YOUR_KEY_HERE στο αρχείο google_maps_api.xml Στην συνέχεια είσαστε έτοιμοι να δείτε τον πρώτο σας χάρτη. Το layout του Map Activity Το αρχείο XML του layout λογικά τώρα θα έχει τα στοιχεία από ένα Fragment με ένα Map. Το fragment είναι ουσιαστικά ένα τμήμα κώδικα, εδώ για χάρτη. <fragment xmlns:android="http://schemas.android.com/apk/res/android" xmlns:map="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:id="@+id/map" android:name="com.google.android.gms.maps.supportmapfragment" android:layout_width="match_parent" android:layout_height="match_parent" tools:context="gr.digiexplore.mymapsapplication.mapsactivity" /> Το αρχείο Java του χάρτη public class MapsActivity extends FragmentActivity implements OnMapReadyCallback { private GoogleMap mmap; protected void oncreate(bundle savedinstancestate) { super.oncreate(savedinstancestate); setcontentview(r.layout.activity_maps); // Obtain the SupportMapFragment and get notified when the map is ready to be used. SupportMapFragment mapfragment = (SupportMapFragment) getsupportfragmentmanager().findfragmentbyid(r.id.map); mapfragment.getmapasync(this); /** * Manipulates the map once available. * This callback is triggered when the map is ready to be used. * This is where we can add markers or lines, add listeners or move the camera. In this case, * we just add a marker near Sydney, Australia. * If Google Play services is not installed on the device, the user will be prompted to install * it inside the SupportMapFragment. This method will only be triggered once the user has * installed Google Play services and returned to the app. */ public void onmapready(googlemap googlemap) { mmap = googlemap; Σελίδα 3
// Add a marker in Sydney and move the camera LatLng sydney = new LatLng(-34, 151); mmap.addmarker(new MarkerOptions().position(sydney).title("Marker in Sydney")); mmap.movecamera(cameraupdatefactory.newlatlng(sydney)); To default αρχείο Java για το Map activity (για Android Studio 2.2) είναι παραπάνω. Η αρχική θέση είναι το Latitude=-34 και Longitude=151, στην πόλη Σίδνει. Αν το εκτελέσετε λογικά θα δείτε το χάρτη με ένα marker («πινέζα») εκεί. Προσοχή Αν σας εμφανιστεί κάποιο λάθος κατά την εκτέλεση, πιθανώς έχετε βάλει API 22 κατά την δημιουργία του Project σας ή έχετε βάλει συσκευή για τον emulator με API 22. Φροντίστε η συσκευή να μην είναι API 22 και να έχει οπωσδήποτε τα Google APIs ενεργοποιημένα. Επίσης αν σας εμφανιστεί σφάλμα παρόλα αυτά, μπορείτε να προσθέσετε την εντολή multidexenabled true μέσα στο build.gradle (κάτω από το targetsdkversion) 8.2 Customization Εδώ θα δούμε πώς μπορούμε να κάνουμε κάποιες αλλαγές στο χάρτη, όπως αλλαγή Zoom Level και θέσης Μπορούμε να αλλάξουμε το zoom level (επίπεδο εστίασης) επιλέγοντας ένα νέο. Οι τιμές που μπορεί να πάρει είναι από 1 έως 21, με το 21 να είναι το επίπεδο με τη μεγαλύτερη εστίαση. Για παράδειγμα, για να εστιάσει στο επίπεδο 16, γράφουμε την εντολή mmap.movecamera(cameraupdatefactory.zoomto(16)); Για να αλλάξουμε τοποθεσία χρησιμοποιώντας ένα ζεύγος συντεταγμένων, π.χ. (lat,lon) = (35.16, 24.25), γράφουμε LatLng latlon = new LatLng(35.16, 24.25); mmap.movecamera(cameraupdatefactory.newlatlngzoom(latlon, 15)); // 15 ειναι το zoom level ή ισοδύναμα χωρίς zoom βάζουμε απλώς το Σελίδα 4
LatLng latlon = new LatLng(35.16, 24.25); mmap.movecamera(cameraupdatefactory.newlatlng(latlon)); Σελίδα 5
Markers Για να βάλουμε έναν default marker στο σημείο αυτό γράφουμε LatLng latlon = new LatLng(35.16, 24.25); mmap.addmarker(new MarkerOptions().position(latLon).title("Marker in Crete")); Για να αλλάξουμε κάποια στοιχεία του marker στο παραπάνω παράδειγμα, όπως χρώμα, εικονίδιο, κλπ, θα πρέπει να «κολλήσουμε» στο τέλος το αντίστοιχο στοιχείο. Για παράδειγμα, για να αλλάξουμε το χρώμα από το εικονίδιο σε Magenta γράφουμε mmap.addmarker(new MarkerOptions().position(sydney).title("Marker in Crete").icon(BitmapDescriptorFactory.defaultMarker(BitmapDescriptorFactory.HUE_MAGENTA))) ; Αν θέλω να χρησιμοποιήσω custom icon, το γράφω ως εξής.icon(bitmapdescriptorfactory.fromresource(r.drawable.icon_location)); Για να αλλάξω το χάρτη σε Satellite: mmap.setmaptype(googlemap.map_type_satellite); 8.3 Χρήση θέσης του Χρήστη Ένα από τα χαρακτηριστικά που κάνει πανίσχυρες τις εφαρμογές για κινητές συσκευές είναι η δυνατότητα γνώσης της θέσης του χρήστη από το GPS ή από τα κοντινά δίκτυα WiFi και η ανάπτυξη λειτουργιών που έχουν σχέση με αυτή. Εδώ θα κάνετε μια εισαγωγή για το πώς μπορείτε να κάνετε χρήση αυτής της υπηρεσίας. Πώς να θέσετε μια εικονική τοποθεσία στον emulator σας Πριν δούμε πως μπορείτε να χρησιμοποιήσετε τη θέση του χρήστη, είναι καλό να χρησιμοποιήσετε ένα πρόγραμμα που να αλλάζει εικονικά την θέση του emulator, ώστε να μπορείτε να ελέγχετε στον υπολογιστή σας αν λειτουργεί σωστά η εφαρμογή σας. Ένας πολύ εύκολος τρόπος για να το κάνετε αυτό στα Windows, είναι να συνδεθείτε με τον emulator χρησιμοποιώντας την παρακάτω εντολή telnet από το Command Line (cmd). telnet localhost 5554 όπου 5554 είναι η θύρα που έχει ο emulator (θα την βρείτε από το πάνω μέρος που γράφει το όνομά του (δείτε στην παρακάτω εικόνα που είναι το 5554 στον emulator). Εσάς μπορεί να είναι διαφορετική θύρα. Σελίδα 6
*Αν δεν αναγνωρίζει την εντολή telnet, τότε θα πρέπει να ακολουθήσετε τα βήματα εδώ http://social.technet.microsoft.com/wiki/contents/articles/910.windows-7-enabling-telnetclient.aspx για να το ενεργοποιήσετε. Την πρώτη φορά ίσως σας ζητήσει να κάνετε authenticate της σύνδεσης με την εντολή auth <auth_token> όπου <auth_token> είναι ένας κωδικός που θα τον βρείτε μέσα στο αρχείο που σας αναφέρεται (δείτε δίπλα) Αφού τον βρείτε γράψετε την εντολή όπως σας ζητείται και στη συνέχεια θα ανοίξει το Android Console. Πλέον έχετε τον έλεγχο του emulator Μετά μπορείτε να γράψετε την εντολή geo fix 35 25 όπου 35 και 25 είναι ένα παράδειγμα για το latitude και το longitude που θα πάρει ο emulator. Με αυτή την εντολή μπορείτε να αλλάζετε εικονικά την τοποθεσία του emulator σας και να ελέγχετε την εφαρμογή σας. Εισαγωγή του LocationListener στο πρόγραμμά μας Το πρώτο βήμα είναι να τροποποιήσετε τον ορισμό του MainActivity εισάγοντας το public class MainActivity extends AppCompatActivity implements LocationListener ώστε η εφαρμογή να μπορεί να χρησιμοποιήσει τις συναρτήσεις του LocationListener. Σελίδα 7
Θα σας κοκκινήσει γιατί θα πρέπει να εισάγετε τις 4 μεθόδους που θα κάνετε implement Πατήσετε ΟΚ και θα σας τις εισάγει στο πρόγραμμά σας. public void onlocationchanged(location location) { public void onstatuschanged(string s, int i, Bundle bundle) { public void onproviderenabled(string s) { public void onproviderdisabled(string s) { Η onlocationchanged εκτελείται όταν αλλάξει η θέση του χρήστη. Η onstatuschanged εκτελείται όταν αλλάξει η κατάσταση της παροχής της θέσης (π.χ. αν ανοίξει ή κλείσει το GPS) Η onproviderenabled εκτελείται όταν εντοπιστεί η τοποθεσία (π.χ. όταν ανοίξει το GPS) Η onproviderdisabled εκτελείται όταν χαθεί η τοποθεσία (π.χ. όταν κλείσει το GPS) LocationManager Για να πάρετε τον έλεγχο της υπηρεσίας της θέσης του κινητού, χρησιμοποιήστε έναν LocationManager ως εξής: LocationManager locationmanager; protected void oncreate(bundle savedinstancestate) { super.oncreate(savedinstancestate); setcontentview(r.layout.activity_main); locationmanager = (LocationManager) getsystemservice(context.location_service); Παράλληλα θα πρέπει να ορίσετε στο XML του manifest, τo permission για την πρόσβαση στην υπηρεσία της θέσης, είτε από το GPS, είτε από τα τριγύρω δίκτυα, κλπ. <uses-permission android:name="android.permission.access_fine_location" /> <uses-permission android:name="android.permission.access_coarse_location" /> Σελίδα 8
Ορισμός Provider Μια νέα έννοια που πρέπει να εισαχθεί είναι ο Provider, δηλαδή η πληροφορία αν η τοποθεσία έχει επιτευχθεί από το GPS ή από το δίκτυο. Για να πάρουμε τον καλύτερο provider που είναι διαθέσιμος (με κάποια κριτήρια που εμείς θεωρούμε ως καλύτερα για την περίπτωσή μας π.χ. ακρίβεια θέσης, κατανάλωση μπαταρίας, κλπ) γράφουμε το παρακάτω (εδώ ως κριτήρια αφήνουμε το default της συσκευής). LocationManager locationmanager; String provider; protected void oncreate(bundle savedinstancestate) { super.oncreate(savedinstancestate); setcontentview(r.layout.activity_main); locationmanager = (LocationManager) getsystemservice(context.location_service); provider = locationmanager.getbestprovider(new Criteria(), false); Στη συνέχεια παίρνουμε την τελευταία γνωστή θέση του χρήστη: Location location = locationmanager.getlastknownlocation(provider); if(location!= null) { Log.i("Location Info", "Location achieved!"); else { Log.i("Location Info", "Location not found!"); Είμαστε πλέον σε θέση να δούμε τις συντεταγμένες του χρήστη, π.χ. με τον παρακάτω κώδικα public void onlocationchanged(location location) { Double lat = location.getlatitude(); Double lon = location.getlongitude(); Log.i("Location Info: Lat=",lat.toString()); Log.i("Location Info: Lon=",lon.toString()); Σελίδα 9