This Android tutorial is to demonstrate a sample application which will draw path for a route in Google map using Android API v2. This tutorial is a part of Google maps series. I recommend you to go through the previous tutorial Draw lines on Google Maps Android API. This earlier tutorial is to draw straight lines (polyline) between given latitude and longitude.
The example Android app given in this tutorial give opportunity to learn to add markers, zoom to a particular latitude/longitude, draw polylines and draw path along a route in Google map. Pre-requisite is same for all Google maps tutorial and so I am not going to repeat it again, so to setup the development environment, to get the Android API key and related preparations please go through the previous tutorial link given above.
Above shown image is the output of the example Android app. I have chose three locations and drawn path between them. Those three locations are shown by Android markers.
To get the directions to draw the path, I have used the Google Directions API. We just hit the given URL using HTTP request and get json response. This Google service calculates direction between given locations.
package com.javapapers.android.maps.path; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import org.json.JSONObject; import android.graphics.Color; import android.os.AsyncTask; import android.os.Bundle; import android.support.v4.app.FragmentActivity; import android.util.Log; import com.google.android.gms.maps.CameraUpdateFactory; import com.google.android.gms.maps.GoogleMap; import com.google.android.gms.maps.SupportMapFragment; import com.google.android.gms.maps.model.LatLng; import com.google.android.gms.maps.model.MarkerOptions; import com.google.android.gms.maps.model.PolylineOptions; public class PathGoogleMapActivity extends FragmentActivity { private static final LatLng LOWER_MANHATTAN = new LatLng(40.722543, -73.998585); private static final LatLng BROOKLYN_BRIDGE = new LatLng(40.7057, -73.9964); private static final LatLng WALL_STREET = new LatLng(40.7064, -74.0094); GoogleMap googleMap; final String TAG = "PathGoogleMapActivity"; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_path_google_map); SupportMapFragment fm = (SupportMapFragment) getSupportFragmentManager() .findFragmentById(R.id.map); googleMap = fm.getMap(); MarkerOptions options = new MarkerOptions(); options.position(LOWER_MANHATTAN); options.position(BROOKLYN_BRIDGE); options.position(WALL_STREET); googleMap.addMarker(options); String url = getMapsApiDirectionsUrl(); ReadTask downloadTask = new ReadTask(); downloadTask.execute(url); googleMap.moveCamera(CameraUpdateFactory.newLatLngZoom(BROOKLYN_BRIDGE, 13)); addMarkers(); } private String getMapsApiDirectionsUrl() { String waypoints = "waypoints=optimize:true|" + LOWER_MANHATTAN.latitude + "," + LOWER_MANHATTAN.longitude + "|" + "|" + BROOKLYN_BRIDGE.latitude + "," + BROOKLYN_BRIDGE.longitude + "|" + WALL_STREET.latitude + "," + WALL_STREET.longitude; String sensor = "sensor=false"; String params = waypoints + "&" + sensor; String output = "json"; String url = "https://maps.googleapis.com/maps/api/directions/" + output + "?" + params; return url; } private void addMarkers() { if (googleMap != null) { googleMap.addMarker(new MarkerOptions().position(BROOKLYN_BRIDGE) .title("First Point")); googleMap.addMarker(new MarkerOptions().position(LOWER_MANHATTAN) .title("Second Point")); googleMap.addMarker(new MarkerOptions().position(WALL_STREET) .title("Third Point")); } } private class ReadTask extends AsyncTask<String, Void, String> { @Override protected String doInBackground(String... url) { String data = ""; try { HttpConnection http = new HttpConnection(); data = http.readUrl(url[0]); } catch (Exception e) { Log.d("Background Task", e.toString()); } return data; } @Override protected void onPostExecute(String result) { super.onPostExecute(result); new ParserTask().execute(result); } } private class ParserTask extends AsyncTask<String, Integer, List<List<HashMap<String, String>>>> { @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]); PathJSONParser parser = new PathJSONParser(); routes = parser.parse(jObject); } catch (Exception e) { e.printStackTrace(); } return routes; } @Override protected void onPostExecute(List<List<HashMap<String, String>>> routes) { ArrayList<LatLng> points = null; PolylineOptions polyLineOptions = null; // traversing through routes for (int i = 0; i < routes.size(); i++) { points = new ArrayList<LatLng>(); polyLineOptions = new PolylineOptions(); List<HashMap<String, String>> path = routes.get(i); 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); } polyLineOptions.addAll(points); polyLineOptions.width(2); polyLineOptions.color(Color.BLUE); } googleMap.addPolyline(polyLineOptions); } } }
package com.javapapers.android.maps.path; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.net.HttpURLConnection; import java.net.URL; import android.util.Log; public class HttpConnection { public String readUrl(String mapsApiDirectionsUrl) throws IOException { String data = ""; InputStream iStream = null; HttpURLConnection urlConnection = null; try { URL url = new URL(mapsApiDirectionsUrl); urlConnection = (HttpURLConnection) url.openConnection(); urlConnection.connect(); 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(); br.close(); } catch (Exception e) { Log.d("Exception while reading url", e.toString()); } finally { iStream.close(); urlConnection.disconnect(); } return data; } }
package com.javapapers.android.maps.path; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import org.json.JSONArray; import org.json.JSONException; import org.json.JSONObject; import com.google.android.gms.maps.model.LatLng; public class PathJSONParser { public List<List<HashMap<String, String>>> parse(JSONObject jObject) { List<List<HashMap<String, String>>> routes = new ArrayList<List<HashMap<String, String>>>(); JSONArray jRoutes = null; JSONArray jLegs = null; JSONArray jSteps = null; try { jRoutes = jObject.getJSONArray("routes"); /** Traversing all routes */ for (int i = 0; i < jRoutes.length(); i++) { jLegs = ((JSONObject) jRoutes.get(i)).getJSONArray("legs"); List<HashMap<String, String>> path = new ArrayList<HashMap<String, String>>(); /** 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<String, String>(); hm.put("lat", Double.toString(((LatLng) list.get(l)).latitude)); hm.put("lng", Double.toString(((LatLng) list.get(l)).longitude)); path.add(hm); } } routes.add(path); } } } catch (JSONException e) { e.printStackTrace(); } catch (Exception e) { } return routes; } /** * Method Courtesy : * jeffreysambells.com/2010/05/27 * /decoding-polylines-from-google-maps-direction-api-with-java * */ private List<LatLng> decodePoly(String encoded) { List<LatLng> poly = new ArrayList<LatLng>(); 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; } }
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" tools:context=".TaskRoadMap" > <fragment android:id="@+id/map" android:layout_width="wrap_content" android:layout_height="wrap_content" class="com.google.android.gms.maps.SupportMapFragment"/> </RelativeLayout>
<?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.javapapers.android.maps.path" android:versionCode="1" android:versionName="1.0" > <uses-sdk android:minSdkVersion="8" android:targetSdkVersion="18" /> <permission android:name="com.javapapers.android.maps.path.permission.MAPS_RECEIVE" android:protectionLevel="signature" /> <uses-permission android:name="com.javapapers.android.maps.path.permission.MAPS_RECEIVE" /> <uses-permission android:name="android.permission.INTERNET" /> <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" /> <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" /> <uses-feature android:glEsVersion="0x00020000" android:required="true" /> <application android:allowBackup="true" android:icon="@drawable/ic_launcher" android:label="@string/app_name" android:theme="@style/AppTheme" > <activity android:name="com.javapapers.android.maps.path.PathGoogleMapActivity" android:label="@string/title_activity_path_google_map" > <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> <meta-data android:name="com.google.android.maps.v2.API_KEY" android:value="AIzaSyARCTcX8bABCDE_ohscNcALAak-HnjTO5s" /> <meta-data android:name="com.google.android.gms.version" android:value="@integer/google_play_services_version" /> </application> </manifest>
Comments are closed for "Draw Path on Google Maps Android API".
how could i pass the latlng points of route to php using json….help plz
thank alot for your code , but can help me to give direction (nevigator)for moving object
Very helpful tutorial.Thankssss
is this code work for linking more than 3 point ?
Nice piece of code!
Thanks for this tutorial
Perfect running this code.
Thnxxxx
this code crashes when used continuosly
-it gives File not found exception
Another exception iwas facing was the “SSL handshake exception”
Anyone has solution for these?
Hi Joe!
Thank you for the wonderful tutorial.
But why are there “>>” all over the place? I’ve never seen them before except when right shift operators are used. Can you please explain why?
Oops! thanks for pointing out. That’s a mistake. The code highlighter has swallowed some part and showing the remaining. I will fix them now.
I’m so much thankful to you :D
Tried everything, every possible code off the net all in vain except your code.
Very easy working implementation. Frankly did not understand anything of the code. Possibly you could give an explanation for how the code works!
does this code run on android emulator? or only real hand set?
It seems the code has successfully run for you. Did you run it on handset or emulator?
What if i want to add marker dynamically based on latitude and longitude? suppose i have a button to add markers
Why does it say that:
—ln 36
“Multiple markers at this line
– activity_path_google_map cannot be resolved or is
not a field
– Occurrence of ‘setContentView'”
and
—ln 38
“map cannot be resolved or is not a field”
in PathGoogleMapActivity.java, when I try to import it.
It seems like it’s missing the R file.
Hi.
It showing empty map., pls help me
How do i draw path between two city which is enter by user in two edittext and distance between them?
please sir help me
Download the google api in your sdk thats it
Nice Code ..
Your tutorial helped me big time. Thanks
Hi Joe:
In my eclipse. It shows error all over ‘>>’ operator. Can you help me with that?
Regards,
Hemal Adani
I think I found it. I downloaded the code instead of copying it. Let see if that works. Thanks joe.
Hi Joe: The errors are resolved with downloaded code. Thanks. I’ll check on device now.
The code worked for me. Drawed Route as per I needed. Thank you.
Save my life last minute.
Thank s a lot. It has been a long time i been trying to do something like this
What kind of google api do you mention?
I have got this error that points to manifest.
error: Error: No resource found that matches the given name (at ‘value’ with value ‘@integer/google_play_services_version’).
Hi,
the URL, which is being generated in the code is wrong :
it should be like :
“https://maps.googleapis.com/maps/api/directions/json?origin=17.449797,78.373037&destination=17.47989,78.390095&%20waypoints=optimize:true|17.449797,78.373037||17.47989,78.390095&sensor=false”
I agree with Harshil. URL generated in the above code miss origin and destination, which are required feilds.
Refer this: https://developers.google.com/maps/documentation/directions/
I was facing error:
java.lang.NullPointerException: Attempt to invoke interface method ‘int java.util.List.size()’ on a null object reference
as URL was not returning anything.
Apart from URL thing, everything else works pretty smooth.
Nice work Joe!
java.lang.NoClassDefFoundError: Failed resolution of: Lcom/google/android/gms/maps/model/LatLng
It gives me a NullPointerException in for loop
” for (int i = 0; i < routes.size(); i++) {"
your code is not working
It seems you need to add origin and destination to url.
Replace this:
String params = waypoints + “&” + sensor;
With this:
String origin = “origin=” + LOWER_MANHATTAN.latitude + “,” + LOWER_MANHATTAN.longitude;
String destination = “destination=” + WALL_STREET.latitude + “,” + WALL_STREET.longitude;
String params = origin + “&” + destination + “&” + waypoints + “&” + sensor;
Thanks bro.. :)
I am unable to run. It says Unable to instantiate activity…
The way it worked for me:
Replace this:
String params = waypoints + “&” + sensor;
With this:
String origin = “origin=” + LOWER_MANHATTAN.latitude + “,” + LOWER_MANHATTAN.longitude;
String destination = “destination=” + WALL_STREET.latitude + “,” + WALL_STREET.longitude;
String params = origin + “&” + destination + “&%20” + waypoints + “&” + sensor;
Thanks for such a nice tutorial. Just needed to change the URL.
error opening trace file: No such file or directory (2)