Учебники для Android на карте Google: рисование маршрутов между двумя точками
Опубликовано: 2018-05-30В этом посте мы обсудим, как нарисовать маршрут на Google Maps между двумя точками.

Во-первых, нам нужна интеграция с Google Map в нашем приложении. Для этого посетите
- https://developers.google.com/maps/documentation/android-api/signup
- Нажмите кнопку "Получить ключ".
Вы увидите диалоговое окно, подобное приведенному ниже.

Создайте новый проект и нажмите «Далее». Вам будет представлен ключ API, подобный приведенному ниже.

Предположим, если вы решите ограничить использование этого ключа, нажмите «Консоль API». В противном случае нажмите ГОТОВО.
В консоли API вы можете ограничить использование ключа только для веб-сайтов, приложений Android, приложений IOS и т. Д.
Нажав на консоль API, вы будете перенаправлены на другую страницу с датой создания, созданием и т. Д. Выберите ключ API, в котором он должен быть ограничен, а затем нажмите переключатель приложений Android.
Предположим, вы хотите ограничить использование приложений Android, добавить имя пакета и отпечаток пальца.
Вы можете получить имя пакета из файла Androidmanifest.xml .

Чтобы добавить отпечаток пальца, вы должны получить сертификат SHA-1. Для этого зайдите в Android Studio и откройте файл Gradle в правом углу.
Далее нажмите Град приложения >> Задачи >> Android >> подписывающий отчет.

Скопируйте сертификат SHA-1 и вставьте его в поле отпечатка SHA-1, как показано на изображении выше. Наконец, нажмите кнопку СОХРАНИТЬ.
Теперь создайте новый проект Android с именем, доменом компании и другими деталями. Выберите свою версию Android как Lollipop и выберите маршрут рисования в Google Map Activity, как показано ниже. Теперь нажмите кнопку «Далее» и «Готово».

После создания проекта вы можете увидеть некоторые файлы, такие как
- MapsActivity.java
- Activity_maps.xml
- google_maps-api.xml
Сначала измените файл google_map_api.xml. В этот файл добавьте созданный нами ранее ключ API Google.
<string name="google_maps_key" templateMergeStrategy="preserve" translatable="false">API Key</string>Затем измените файл Androidmanifest.xml
- Подключение к Интернету - для связи с API и определения местоположения.
- READ_GSERVICES - всякий раз, когда приложение хочет использовать Google Service Framework
- ACCESS_COARSE_LOCATION - он определит местоположение пользователя с помощью Wi-Fi и мобильных данных. Это даст примерное местоположение
- ACCESS_FINE_LOCATION - он определит местоположение пользователя с помощью GPS. Это даст вам точное местоположение.
- Также добавьте тег метаданных в тег приложения, который содержит значение ключа API.
Файл Androidmanifest.xml выглядит следующим образом
<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>Теперь измените файл build.gradle. При изменении убедитесь, что вы добавили две зависимости, а именно:
- реализация 'com.google.android.gms: play-services-maps: 11.8.0'
- реализация 'com.google.android.gms: play-services-location: 11.8.0'
В то время как первая зависимость используется для отображения карты Google, вторая зависимость используется для получения местоположения Google и распознавания активности.
Итак, файл build.gradle выглядит так, как показано ниже
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' }Начнем с MapsActivity. В этом упражнении мы устанавливаем файл макета с именем Activity_maps.
В этом XML-файле определите фрагмент и объявите идентификатор и имя для фрагмента. Наконец, xml выглядит так, как показано ниже .
<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" />Здесь вы объявляете android: name = "com.google.android.gms.maps.SupportMapFragment", потому что мы расширяем действие из FragmentActivity. Если вы хотите использовать MapFragment, вы можете расширить Activity.
Затем расширьте MapsActivity, где идентификатор определяется следующим образом:
Final SupportMapFragment mapFragment =(SupportMapFragment) getSupportFragmentManager() .findFragmentById(R.id.map);Давайте разделим код здесь и обсудим один за другим. Сначала вам нужно создать экземпляр класса GoogleMap.
Теперь объявите карту onClick 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)); } } });Показанный выше код будет выполнен, когда пользователь коснется экрана Android. Это используется для размещения маркера в точках, между которыми будет проведен путь.
MarkerPoints.get () используется для доступа и хранения координат двух точек. Он будет сохранен в исходной и конечной координатах LatLng.

И getUrl используется для получения URL-адреса и реализуется с помощью Async Task.
Асинхронная задача: Асинхронная задача - это абстрактный класс, предоставляемый Android, который помогает использовать поток пользовательского интерфейса. Класс Async Task позволяет нам выполнять длительные операции или фоновые операции и отображать результаты в потоке пользовательского интерфейса, не затрагивая основной поток. Асинхронная задача используется для выполнения задач / операций, которые необходимо выполнять в фоновом режиме асинхронно. В классе Async Task есть два метода.
- doInbackground: В этом методе будет реализована задача.
- onPostExecute: в этом методе будет показан результат.
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: используется для получения URL-адреса из веб-службы, и его результат будет проанализирован с помощью ParserTask. Это также асинхронная задача.
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; }Здесь данные будут возвращены в виде Json. какой пользователь может получить с помощью HttpURLConnection.
Задача парсера: Определите новый класс с именем ParserTask, который расширяет AsyncTask. Анализируйте данные Json, возвращаемые методом 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"); } } }Здесь doInBackround проанализирует данные. В методе onPostExecute мы добавим ломаную линию для рисования маршрута на Google Map.
Следуя этим методам, мы анализируем данные в другой класс, то есть 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; } }С помощью метода синтаксического анализа вы получаете данные Json, которые могут разделить JSONArray с помощью getJSONArray. Пройдите все маршруты, точки и т. Д. И добавьте все точки пересечения в список.
routes.add (путь);
Нарисуйте маршрут на карте Google с помощью ломаной линии. Это делается в методе onPostExecute, в котором класс 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"); } }Вышеупомянутые точки берутся из результата и рисуют маршрут на картах Google. Здесь точки ArrayList используются для хранения позиций широты и долготы на карте Google.
Наконец, маршрут нарисован на Google Map с помощью polyLine: lineOptions.addAll (points);
Добавьте ломаную линию на карту, например: mMap.addPolyline (lineOptions);
Наконец запустите приложение. Он будет работать успешно. Вывод на экран показан ниже.

