Samouczki Androida na mapie Google: rysowanie tras między dwoma punktami

Opublikowany: 2018-05-30

W tym poście omówimy Jak narysować trasę na Mapach Google między dwoma punktami.

Samouczki na Androida

Po pierwsze, potrzebujemy integracji Google Map w naszej aplikacji. Aby to zrobić, odwiedź

  • https://developers.google.com/maps/documentation/android-api/signup
  • Kliknij przycisk Zdobądź klucz

Zobaczysz okno dialogowe podobne do poniższego.

Włącz interfejs API Map Google na Androida

Utwórz nowy projekt i kliknij Dalej. Otrzymasz klucz API, taki jak ten poniżej.

Klucz interfejsu API Map Google na Androida

Załóżmy, że jeśli zdecydujesz się ograniczyć użycie tego klucza, kliknij Konsola API. W przeciwnym razie kliknij GOTOWE.

W Konsoli API możesz ograniczyć użycie klucza tylko dla stron internetowych, aplikacji na Androida, aplikacji na iOS itp.

Po kliknięciu konsoli API zostaniesz przekierowany na inną stronę z datą utworzenia, Utworzony przez itp. Wybierz klucz API, do którego ma być ograniczony, a następnie kliknij przycisk opcji Android Apps.

Załóżmy, że chcesz ograniczyć użycie do aplikacji na Androida, dodać nazwę pakietu i odcisk palca.

Nazwę pakietu można pobrać z pliku Androidmanifest.xml .

Dodaj nazwę pakietu

Aby dodać odcisk palca należy uzyskać certyfikat SHA-1. W tym celu odwiedź Android Studio i otwórz plik Gradle w prawym rogu.

Następnie kliknij Gradle aplikacji >> Zadania >> android >> raport podpisywania

Projekty Gradle

Skopiuj certyfikat SHA-1 i wklej go w polu odcisku palca SHA-1, jak pokazano na powyższym obrazku. Na koniec kliknij przycisk ZAPISZ.

Teraz utwórz nowy projekt Androida z nazwą, domeną firmy i innymi szczegółami. Wybierz wersję Androida jako Lollipop i wybierz trasę rysowania w Google Map Activity, jak pokazano poniżej. Teraz kliknij przycisk Dalej i zakończ.

Dodaj aktywność do telefonu komórkowego

Po utworzeniu projektu możesz zobaczyć niektóre pliki, takie jak

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

Najpierw zmień plik google_map_api.xml. W tym pliku dodaj klucz Google API, który utworzyliśmy wcześniej.

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

Następnie zmień plik Androidmanifest.xml

  • Połączenie internetowe - Aby komunikować się z API i uzyskać lokalizację
  • READ_GSERVICES - Gdy aplikacja chce korzystać z Google Service Framework
  • ACCESS_COARSE_LOCATION - określi lokalizację użytkownika za pomocą Wifi i danych mobilnych. Da to przybliżoną lokalizację
  • ACCESS_FINE_LOCATION - określi lokalizację użytkownika za pomocą GPS. Poda ci dokładną lokalizację.
  • Dodaj również tag meta-data w tagu aplikacji, który zawiera wartość klucza API

Plik Androidmanifest.xml wygląda jak poniżej

 <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>

Teraz zmień plik build.gradle. Podczas zmiany upewnij się, że dodałeś dwie zależności, którymi są:

  • implementacja „com.google.android.gms:play-services-maps:11.8.0”
  • implementacja „com.google.android.gms:play-services-location:11.8.0”

Podczas gdy pierwsza zależność jest używana do wyświetlania mapy google, druga zależność jest używana do uzyskiwania lokalizacji Google i rozpoznawania aktywności.

Tak więc plik build.gradle wygląda jak poniżej

 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' }

Zacznijmy od MapsActivity. W tym ćwiczeniu ustawiamy plik układu o nazwie Activity_maps

W tym pliku xml zdefiniuj fragment i zadeklaruj identyfikator i nazwę fragmentu. Wreszcie plik xml jest taki, jak pokazano poniżej .

 <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" />

Tutaj deklarujesz Androida: name="com.google.android.gms.maps.SupportMapFragment", ponieważ rozszerzamy aktywność z FragmentActivity. Jeśli chcesz korzystać z MapFragment, możesz rozszerzyć Aktywność.

Następnie rozszerz MapsActivity, gdzie identyfikator jest zdefiniowany w ten sposób:

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

Podzielmy kod tutaj i omówmy jeden po drugim. Najpierw musisz utworzyć instancję klasy GoogleMap.

Teraz zadeklaruj mapę naClick 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)); } } });

Powyższy kod zostanie wykonany, gdy użytkownik dotknie ekranu Androida. Służy do umieszczania znacznika w punktach, pomiędzy którymi zostanie narysowana ścieżka.

MarkerPoints.get() służy do uzyskiwania dostępu i przechowywania współrzędnych dwóch punktów. Będzie on przechowywany w miejscu pochodzenia i przeznaczenia LatLng.

GetUrl jest używany do pobierania adresu URL i implementowany za pomocą zadania asynchronicznego.

Async Task: Async Task to klasa abstrakcyjna dostarczana przez system Android, która pomaga korzystać z wątku interfejsu użytkownika. Klasa Async Task pozwala nam wykonywać długotrwałe operacje lub operacje w tle i wyświetlać wyniki w wątku interfejsu użytkownika bez wpływu na główny wątek. Zadanie asynchroniczne służy do uruchamiania zadań/operacji, które muszą być wykonywane w tle asynchronicznie. W klasie Async Task istnieją dwie metody.

  • doInbackground : Zadanie zostanie zaimplementowane w tej metodzie.
  • onPostExecute: Wynik zostanie wyświetlony w tej metodzie.
 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: Służy do pobierania adresu URL z usługi sieciowej, a jego wynik zostanie przeanalizowany za pomocą ParserTask. Jest to również zadanie asynchroniczne.

 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; }

Tutaj dane zostaną zwrócone w postaci Json. który użytkownik może uzyskać za pomocą HttpURLConnection.

Parser Task: Zdefiniuj nową klasę o nazwie ParserTask, która rozszerza AsyncTask. Przeanalizuj dane Json zwrócone przez metodę 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"); } } }

Tutaj „doInBackround” przeanalizuje dane. W metodzie „onPostExecute” dodamy polilinię do narysowania trasy na Google Map.

Postępując zgodnie z tymi metodami, parsujemy dane do innej klasy, tj. 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; } }

Dzięki metodzie parse otrzymujesz dane Json, które mogą podzielić JSONArray za pomocą getJSONArray. Przemierz wszystkie trasy, punkty itp. i dodaj wszystkie punkty przejazdu do listy.

trasy.dodaj(ścieżka);

Narysuj trasę na mapie Google za pomocą polilinii. Odbywa się to w metodzie onPostExecute, w której klasa 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"); } }

Powyższe punkty pobierane są z wyniku i rysują trasę na mapach Google. Tutaj punkty ArrayList są używane do przechowywania pozycji szerokości i długości geograficznej na mapie Google.

W końcu trasa jest rysowana na Google Map za pomocą polyLine: lineOptions.addAll(points);

Dodaj polilinię do mapy, np.: mMap.addPolyline(lineOptions);

Na koniec uruchom aplikację. Będzie działać pomyślnie. Dane wyjściowe ekranu są pokazane poniżej.

Android Blog Mapa Aktualna pozycja

Wyniki na ekranie mapy trasy