Tutorial Android su Google Map: tracciare percorsi tra due punti

Pubblicato: 2018-05-30

In questo post parleremo di come disegnare un percorso su Google Maps tra due punti.

Tutorial Android

Innanzitutto, abbiamo bisogno di un'integrazione di Google Map sulla nostra app. Per farlo, visita

  • https://developers.google.com/maps/documentation/android-api/signup
  • Fare clic sul pulsante Ottieni una chiave

Vedrai una finestra di dialogo simile a quella qui sotto.

Abilita l'API Android di Google Maps

Crea un nuovo progetto e fai clic su Avanti. Ti verrà presentata una chiave API come quella qui sotto.

Chiave API Android di Google Maps

Supponiamo che, se scegli di limitare l'utilizzo di questa chiave, fai clic su Console API. Altrimenti, fai clic su FATTO.

Nella console API puoi limitare l'utilizzo della chiave solo per siti Web, app Android, app IOS ecc.

Facendo clic sulla Console API, verrai reindirizzato a un'altra pagina con la data di creazione, Creato da ecc. Scegli la chiave API in cui dovrebbe essere limitato e quindi fai clic sul pulsante di opzione App Android.

Supponiamo che tu voglia limitare l'utilizzo alle tue app Android, aggiungere il nome del pacchetto e l'impronta digitale.

Puoi ottenere il nome del pacchetto dal file Androidmanifest.xml .

Aggiungi nome pacchetto

Per aggiungere l'impronta digitale, è necessario ottenere il certificato SHA-1. Per questo, visita Android Studio e apri il file Gradle nell'angolo destro.

Inoltre, fai clic su App gradle >> Attività >> Android >> signingreport

Progetti Gradle

Copia il certificato SHA-1 e incollalo nella casella delle impronte digitali SHA-1 come mostrato nell'immagine sopra. Infine, fai clic sul pulsante SALVA.

Ora crea un nuovo progetto Android con il nome, il dominio dell'azienda e altri dettagli. Scegli la tua versione Android come Lollipop e scegli il percorso di disegno su Google Map Activity come mostrato di seguito. Ora fai clic sul pulsante Avanti e Fine.

Aggiungi attività al cellulare

Dopo aver creato il progetto puoi vedere alcuni file come

  • MapsActivity.java
  • Activity_maps.xml
  • google_maps-api.xml

Innanzitutto, cambia google_map_api.xml. In questo file, aggiungi la chiave API di Google che abbiamo creato in precedenza.

 <string name="google_maps_key" templateMergeStrategy="preserve" translatable="false">API Key</string>

Successivamente, cambia il file Androidmanifest.xml

  • Connessione Internet - Per comunicare con API e ottenere la posizione
  • READ_GSERVICES - Ogni volta che un'app desidera utilizzare Google Service Framework
  • ACCESS_COARSE_LOCATION - Determina la posizione dell'utente utilizzando Wi-Fi e dati mobili. Darà posizione approssimativa
  • ACCESS_FINE_LOCATION- Determina la posizione dell'utente utilizzando il GPS. Ti darà la posizione esatta.
  • Inoltre, aggiungi il tag dei metadati nel tag dell'applicazione che contiene il valore della chiave API

Il file Androidmanifest.xml ha il seguente aspetto

 <manifest xmlns:andro package="com.example.drawroutes"> <uses-permission android:name="android.permission.INTERNET" /> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> <uses-permission android:name="com.google.android.providers.gsf.permission.READ_GSERVICES" /> <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" /> <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" /> <application android:allowBackup="true" android:icon="@mipmap/ic_launcher" android:label="@string/app_name" android:roundIcon="@mipmap/ic_launcher_round" android:supportsRtl="true" android:theme="@style/AppTheme"> <meta-data android:name="com.google.android.geo.API_KEY" android:value="@string/google_maps_key" /> <activity android:name=".MapsActivity" android:label="@string/title_activity_maps"> <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> </application> </manifest>

Ora cambia il file build.gradle. Durante la modifica, assicurati di aggiungere le due dipendenze, che sono:

  • implementazione 'com.google.android.gms:play-services-maps:11.8.0'
  • implementazione 'com.google.android.gms:play-services-location:11.8.0'

Mentre la prima dipendenza viene utilizzata per visualizzare la mappa di Google, la seconda viene utilizzata per ottenere la posizione di Google e il riconoscimento dell'attività.

Quindi il file build.gradle appare come sotto

 apply plugin: 'com.android.application' android { compileSdkVersion 26 defaultConfig { applicationId "com.example.drawroutes" minSdkVersion 19 targetSdkVersion 26 versionCode 1 versionName "1.0" testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" } buildTypes { release { minifyEnabled false proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' } } } dependencies { implementation fileTree(dir: 'libs', include: ['*.jar']) implementation 'com.android.support:appcompat-v7:26.1.0' implementation 'com.google.android.gms:play-services-maps:11.8.0' implementation 'com.google.android.gms:play-services-location:11.8.0' }

Cominciamo con MapsActivity. In questa attività impostiamo il file di layout denominato Activity_maps

In questo file xml definire un frammento e dichiarare id e nome per il frammento. Infine l'xml è come mostrato di seguito .

 <fragment xmlns:andro xmlns:tools="schemas.android.com/tools" android: android:name="com.google.android.gms.maps.SupportMapFragment" android:layout_width="match_parent" android:layout_height="match_parent" tools:context="com.example.drawroutes.MapsActivity" />

Qui stai dichiarando Android: name="com.google.android.gms.maps.SupportMapFragment" perché stiamo estendendo l'attività da FragmentActivity. Se vuoi usare MapFragment, puoi estendere Activity.

Successivamente, estendi MapsActivity dove l'id è definito in questo modo:

 Final SupportMapFragment mapFragment =(SupportMapFragment) getSupportFragmentManager() .findFragmentById(R.id.map);

Dividiamo qui il codice e discutiamone uno dopo l'altro. All'inizio, devi creare un'istanza della classe GoogleMap.

Ora dichiara la mappa suClick Listner

 mMap.setOnMapClickListener(new GoogleMap.OnMapClickListener() { @Override public void onMapClick(LatLng point) { // Already two locations if (MarkerPoints.size() > 1) { MarkerPoints.clear(); mMap.clear(); } // Adding new item to the ArrayList MarkerPoints.add(point); // Creating MarkerOptions MarkerOptions options = new MarkerOptions(); // Setting the position of the marker options.position(point); /** * For the start location, the color of marker is GREEN and * for the end location, the color of marker is RED. */ if (MarkerPoints.size() == 1) { options.icon(BitmapDescriptorFactory.defaultMarker(BitmapDescriptorFactory.HUE_GREEN)); } else if (MarkerPoints.size() == 2) { options.icon(BitmapDescriptorFactory.defaultMarker(BitmapDescriptorFactory.HUE_RED)); } // Add new marker to the Google Map Android API V2 mMap.addMarker(options); // Checks, whether start and end locations are captured if (MarkerPoints.size() >= 2) { LatLng origin = MarkerPoints.get(0); LatLng dest = MarkerPoints.get(1); // Getting URL to the Google Directions API String url = getUrl(origin, dest); Log.d("onMapClick", url.toString()); FetchUrl FetchUrl = new FetchUrl(); // Start downloading json data from Google Directions API FetchUrl.execute(url); //move map camera mMap.moveCamera(CameraUpdateFactory.newLatLng(origin)); mMap.animateCamera(CameraUpdateFactory.zoomTo(11)); } } });

Il codice mostrato sopra verrà eseguito quando l'utente tocca uno schermo Android. Questo è usato per posizionare il marcatore nei punti tra i quali verrà disegnato il percorso.

MarkerPoints.get() viene utilizzato per accedere e memorizzare le coordinate dei due punti. Verrà memorizzato in LatLng origine e destinazione.

E getUrl viene utilizzato per recuperare l'URL e implementato utilizzando Async Task.

Async Task: Async Task è una classe astratta fornita da Android, che aiuta a usare il thread dell'interfaccia utente. La classe Async Task ci consente di eseguire operazioni a esecuzione prolungata o operazioni in background e visualizzare i risultati sul thread dell'interfaccia utente senza influire sul thread principale. Async Task viene utilizzato per eseguire attività/operazioni che devono essere eseguite in background in modo asincrono. Nella classe Async Task ci sono due metodi.

  • doInbackground: l'attività verrà implementata in questo metodo.
  • onPostExecute: il risultato verrà mostrato in questo metodo.
 private class FetchUrl extends AsyncTask<String, Void, String> { @Override protected String doInBackground(String... url) { // For storing data from web service String data = ""; try { // Fetching the data from web service data = downloadUrl(url[0]); Log.d("Background Task data", data.toString()); } catch (Exception e) { Log.d("Background Task", e.toString()); } return data; } @Override protected void onPostExecute(String result) { super.onPostExecute(result); ParserTask parserTask = new ParserTask(); // Invokes the thread for parsing the JSON data parserTask.execute(result); } }

downloadUrl: viene utilizzato per recuperare l'URL dal servizio Web e il suo risultato verrà analizzato utilizzando ParserTask. Anche questa è un'attività asincrona.

 private String downloadUrl(String strUrl) throws IOException { String data = ""; InputStream iStream = null; HttpURLConnection urlConnection = null; try { URL url = new URL(strUrl); // Creating an http connection to communicate with url urlConnection = (HttpURLConnection) url.openConnection(); // Connecting to url urlConnection.connect(); // Reading data from url iStream = urlConnection.getInputStream(); BufferedReader br = new BufferedReader(new InputStreamReader(iStream)); StringBuffer sb = new StringBuffer(); String line = ""; while ((line = br.readLine()) != null) { sb.append(line); } data = sb.toString(); Log.d("downloadUrl", data.toString()); br.close(); } catch (Exception e) { Log.d("Exception", e.toString()); } finally { iStream.close(); urlConnection.disconnect(); } return data; }

Qui i dati verranno restituiti sotto forma di Json. quale utente può ottenere utilizzando HttpURLConnection.

Compito del parser: definire una nuova classe con il nome ParserTask che estende AsyncTask. Analizza i dati Json restituiti dal metodo downloadUrl.

 private class ParserTask extends AsyncTask<String, Integer, List<List<HashMap<String, String>>>> { // Parsing the data in non-ui thread @Override protected List<List<HashMap<String, String>>> doInBackground(String... jsonData) { JSONObject jObject; List<List<HashMap<String, String>>> routes = null; try { jObject = new JSONObject(jsonData[0]); Log.d("ParserTask",jsonData[0].toString()); DataParser parser = new DataParser(); Log.d("ParserTask", parser.toString()); // Starts parsing data routes = parser.parse(jObject); Log.d("ParserTask","Executing routes"); Log.d("ParserTask",routes.toString()); } catch (Exception e) { Log.d("ParserTask",e.toString()); e.printStackTrace(); } return routes; } // Executes in UI thread, after the parsing process @Override protected void onPostExecute(List<List<HashMap<String, String>>> result) { ArrayList<LatLng> points; PolylineOptions lineOptions = null; // Traversing through all the routes for (int i = 0; i < result.size(); i++) { points = new ArrayList<>(); lineOptions = new PolylineOptions(); // Fetching i-th route List<HashMap<String, String>> path = result.get(i); // Fetching all the points in i-th route for (int j = 0; j < path.size(); j++) { HashMap<String, String> point = path.get(j); double lat = Double.parseDouble(point.get("lat")); double lng = Double.parseDouble(point.get("lng")); LatLng position = new LatLng(lat, lng); points.add(position); } // Adding all the points in the route to LineOptions lineOptions.addAll(points); lineOptions.width(10); lineOptions.color(Color.RED); Log.d("onPostExecute","onPostExecute lineoptions decoded"); } // Drawing polyline in the Google Map for the i-th route if(lineOptions != null) { mMap.addPolyline(lineOptions); } else { Log.d("onPostExecute","without Polylines drawn"); } } }

Qui, il "doInBackround" analizzerà i dati. Nel metodo “onPostExecute” aggiungeremo la polilinea per disegnare il percorso su Google Map.

Seguendo questi metodi, stiamo analizzando i dati in un'altra classe, ad esempio DataParser

 class DataParser { List<List<HashMap<String,String>>> parse(JSONObject jObject){ List<List<HashMap<String, String>>> routes = new ArrayList<>() ; JSONArray jRoutes; JSONArray jLegs; JSONArray jSteps; try { jRoutes = jObject.getJSONArray("routes"); /** Traversing all routes */ for(int i=0;i<jRoutes.length();i++){ jLegs = ( (JSONObject)jRoutes.get(i)).getJSONArray("legs"); List path = new ArrayList<>(); /** Traversing all legs */ for(int j=0;j<jLegs.length();j++){ jSteps = ( (JSONObject)jLegs.get(j)).getJSONArray("steps"); /** Traversing all steps */ for(int k=0;k<jSteps.length();k++){ String polyline = ""; polyline = (String)((JSONObject)((JSONObject)jSteps.get(k)).get("polyline")).get("points"); List<LatLng> list = decodePoly(polyline); /** Traversing all points */ for(int l=0;l<list.size();l++){ HashMap<String, String> hm = new HashMap<>(); hm.put("lat", Double.toString((list.get(l)).latitude) ); hm.put("lng", Double.toString((list.get(l)).longitude) ); path.add(hm); } } routes.add(path); } } } catch (JSONException e) { e.printStackTrace(); }catch (Exception e){ } return routes; } /** * Method to decode polyline points * */ private List<LatLng> decodePoly(String encoded) { List<LatLng> poly = new ArrayList<>(); int index = 0, len = encoded.length(); int lat = 0, lng = 0; while (index < len) { int b, shift = 0, result = 0; do { b = encoded.charAt(index++) - 63; result |= (b & 0x1f) << shift; shift += 5; } while (b >= 0x20); int dlat = ((result & 1) != 0 ? ~(result >> 1) : (result >> 1)); lat += dlat; shift = 0; result = 0; do { b = encoded.charAt(index++) - 63; result |= (b & 0x1f) << shift; shift += 5; } while (b >= 0x20); int dlng = ((result & 1) != 0 ? ~(result >> 1) : (result >> 1)); lng += dlng; LatLng p = new LatLng((((double) lat / 1E5)), (((double) lng / 1E5))); poly.add(p); } return poly; } }

Con il metodo parse ottieni dati Json che possono dividere JSONArray usando getJSONArray. Attraversa tutti i percorsi, i punti, ecc. e aggiungi tutti i punti di attraversamento all'elenco.

route.add(percorso);

Disegna il percorso sulla mappa di Google utilizzando la polilinea. Questo viene fatto nel metodo onPostExecute in cui la classe ParseTask AsyncTask.

 @Override protected void onPostExecute(List<List<HashMap<String, String>>> result) { ArrayList<LatLng> points; PolylineOptions lineOptions = null; // Traversing through all the routes for (int i = 0; i < result.size(); i++) { points = new ArrayList<>(); lineOptions = new PolylineOptions(); // Fetching i-th route List<HashMap<String, String>> path = result.get(i); // Fetching all the points in i-th route for (int j = 0; j < path.size(); j++) { HashMap<String, String> point = path.get(j); double lat = Double.parseDouble(point.get("lat")); double lng = Double.parseDouble(point.get("lng")); LatLng position = new LatLng(lat, lng); points.add(position); } // Adding all the points in the route to LineOptions lineOptions.addAll(points); lineOptions.width(10); lineOptions.color(Color.RED); Log.d("onPostExecute","onPostExecute lineoptions decoded"); } // Drawing polyline in the Google Map for the i-th route if(lineOptions != null) { mMap.addPolyline(lineOptions); } else { Log.d("onPostExecute","without Polylines drawn"); } }

I punti di cui sopra vengono recuperati dal risultato e tracciano un percorso su Google Maps. Qui i punti ArrayList vengono utilizzati per memorizzare le posizioni di latitudine e longitudine su Google Map.

Infine, il percorso viene disegnato su Google Map utilizzando polyLine: lineOptions.addAll(points);

Aggiungi la polilinea alla mappa come: mMap.addPolyline(lineOptions);

Infine esegui l'applicazione. Verrà eseguito correttamente. L'output dello schermo è come mostrato di seguito.

Android Blog Mappa Posizione attuale

Risultato della schermata della mappa del percorso