GoogleマップのAndroidチュートリアル:2点間のルートの描画
公開: 2018-05-30この投稿では、2地点間でGoogleマップにルートを描く方法について説明します。

まず、アプリにGoogleマップを統合する必要があります。 これを行うには、次のWebサイトにアクセスしてください。
- 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ファイルを開きます。
さらに、App gradle >> Tasks >> android >> signingreportをクリックします

上の画像に示すように、SHA-1証明書をコピーして、SHA-1指紋ボックスに貼り付けます。 最後に、[保存]ボタンをクリックします。
次に、名前、会社のドメイン、その他の詳細を使用して新しいAndroidプロジェクトを作成します。 AndroidのバージョンをLollipopとして選択し、以下に示すようにGoogleマップアクティビティで描画ルートを選択します。 次に、[次へ]をクリックして[完了]ボタンをクリックします。

プロジェクトを作成した後、次のようないくつかのファイルを見ることができます
- MapsActivity.java
- Activity_maps.xml
- google_maps-api.xml
まず、 google_map_api.xmlを変更します。 このファイルに、前に作成したGoogleAPIキーを追加します。
<string name="google_maps_key" templateMergeStrategy="preserve" translatable="false">API Key</string>次に、Androidmanifest.xmlファイルを変更します
- インターネット接続-APIと通信し、場所を取得する
- READ_GSERVICES-アプリがGoogleサービスフレームワークを使用したいときはいつでも
- ACCESS_COARSE_LOCATION-Wifiとモバイルデータを使用してユーザーの場所を特定します。 おおよその位置を示します
- 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>次に、inbuild.gradleファイルを変更します。 変更するときは、次の2つの依存関係を必ず追加してください。
- 実装 'com.google.android.gms:play-services-maps:11.8.0'
- 実装 'com.google.android.gms:play-services-location:11.8.0'
1番目の依存関係はGoogleマップを表示するために使用され、2番目の依存関係は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ファイルでフラグメントを定義し、フラグメントのIDと名前を宣言します。 最後に、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" />ここでは、FragmentActivityからアクティビティを拡張しているため、 androidを宣言しています:name = "com.google.android.gms.maps.SupportMapFragment" 。 MapFragmentを使用する場合は、Activityを拡張できます。
次に、IDが次のように定義されているMapsActivityを拡張します。
Final SupportMapFragment mapFragment =(SupportMapFragment) getSupportFragmentManager() .findFragmentById(R.id.map);ここでコードを分割し、次々に議論しましょう。 まず、GoogleMapクラスをインスタンス化する必要があります。
次に、クリックリストナーでマップを宣言します
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()は、2つのポイントの座標にアクセスして保存するために使用されます。 LatLngの起点と終点に保存されます。
また、 getUrlはURLをフェッチするために使用され、非同期タスクを使用して実装されます。
非同期タスク:非同期タスクはAndroidが提供する抽象クラスであり、UIスレッドの使用に役立ちます。 非同期タスククラスを使用すると、メインスレッドに影響を与えることなく、長時間実行操作またはバックグラウンド操作を実行し、結果をUIスレッドに表示できます。 非同期タスクは、バックグラウンドで非同期に実行する必要のあるタスク/操作を実行するために使用されます。 非同期タスククラスには、2つのメソッドがあります。
- 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:これはWebサービスから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を使用して取得できるユーザー。
パーサータスク: AsyncTaskを拡張するParserTaskという名前で新しいクラスを定義します。 downloadUrlメソッドによって返されたJsonデータを解析します。
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マップにルートを描画するためのポリラインを追加します。
これらのメソッドに従うことで、データを別のクラス、つまり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; } }parseメソッドを使用すると、getJSONArrayを使用してJSONArrayを分割できるJsonデータを取得できます。 すべてのルート、ポイントなどをトラバースし、すべてのトラバースポイントをリストに追加します。
ルート.add(パス);
ポリラインを使用してGoogleマップにルートを描画します。 これは、ParseTaskAsyncTaskクラスが含まれるonPostExecuteメソッドで実行されます。
@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マップの緯度と経度の位置を格納するために使用されます。
最後に、ルートはpolyLineを使用してGoogleマップに描画されます。lineOptions.addAll(points);
次のようにポリラインをマップに追加します。mMap.addPolyline(lineOptions);
最後に、アプリケーションを実行します。 正常に実行されます。 画面の出力は以下のようになります。

