By Anupam Chugh
In this tutorial, we’ll be creating an android application that draws a possible google map route between two points. We’ll be using Google Maps Directions API in our application.
Create a new Google Map API Key from the API console using the steps demonstrated in this tutorial. Create a New Android Studio Project and select the template as Google Maps Activity. Add the API key inside the google_maps_api.xml
file that resides inside debug->res->values folder This is how the application should look if you’re using the latest Android Studio.
The
DirectionsJSONParser.java
file is the one that parses the locations and returns the route. decodePoly()
method is then invoked to get the polyline data that’s later drawn on the map.
The MainActivity.java
code is given below.
public class MapsActivity extends FragmentActivity implements OnMapReadyCallback {
private GoogleMap mMap;
ArrayList markerPoints= new ArrayList();
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_maps);
// Obtain the SupportMapFragment and get notified when the map is ready to be used.
SupportMapFragment mapFragment = (SupportMapFragment) getSupportFragmentManager()
.findFragmentById(R.id.map);
mapFragment.getMapAsync(this);
}
@Override
public void onMapReady(GoogleMap googleMap) {
mMap = googleMap;
LatLng sydney = new LatLng(-34, 151);
//mMap.addMarker(new MarkerOptions().position(sydney).title("Marker in Sydney"));
mMap.moveCamera(CameraUpdateFactory.newLatLngZoom(sydney, 16));
mMap.setOnMapClickListener(new GoogleMap.OnMapClickListener() {
@Override
public void onMapClick(LatLng latLng) {
if (markerPoints.size() > 1) {
markerPoints.clear();
mMap.clear();
}
// Adding new item to the ArrayList
markerPoints.add(latLng);
// Creating MarkerOptions
MarkerOptions options = new MarkerOptions();
// Setting the position of the marker
options.position(latLng);
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 = (LatLng) markerPoints.get(0);
LatLng dest = (LatLng) markerPoints.get(1);
// Getting URL to the Google Directions API
String url = getDirectionsUrl(origin, dest);
DownloadTask downloadTask = new DownloadTask();
// Start downloading json data from Google Directions API
downloadTask.execute(url);
}
}
});
}
private class DownloadTask extends AsyncTask {
@Override
protected String doInBackground(String... url) {
String data = "";
try {
data = downloadUrl(url[0]);
} catch (Exception e) {
Log.d("Background Task", e.toString());
}
return data;
}
@Override
protected void onPostExecute(String result) {
super.onPostExecute(result);
ParserTask parserTask = new ParserTask();
parserTask.execute(result);
}
}
private class ParserTask extends AsyncTask<String, Integer, List<List<HashMap>>> {
// Parsing the data in non-ui thread
@Override
protected List<List<HashMap>> doInBackground(String... jsonData) {
JSONObject jObject;
List<List<HashMap>> routes = null;
try {
jObject = new JSONObject(jsonData[0]);
DirectionsJSONParser parser = new DirectionsJSONParser();
routes = parser.parse(jObject);
} catch (Exception e) {
e.printStackTrace();
}
return routes;
}
@Override
protected void onPostExecute(List<List<HashMap>> result) {
ArrayList points = null;
PolylineOptions lineOptions = null;
MarkerOptions markerOptions = new MarkerOptions();
for (int i = 0; i < result.size(); i++) {
points = new ArrayList();
lineOptions = new PolylineOptions();
List<HashMap> path = result.get(i);
for (int j = 0; j < path.size(); j++) {
HashMap 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);
}
lineOptions.addAll(points);
lineOptions.width(12);
lineOptions.color(Color.RED);
lineOptions.geodesic(true);
}
// Drawing polyline in the Google Map for the i-th route
mMap.addPolyline(lineOptions);
}
}
private String getDirectionsUrl(LatLng origin, LatLng dest) {
// Origin of route
String str_origin = "origin=" + origin.latitude + "," + origin.longitude;
// Destination of route
String str_dest = "destination=" + dest.latitude + "," + dest.longitude;
// Sensor enabled
String sensor = "sensor=false";
String mode = "mode=driving";
// Building the parameters to the web service
String parameters = str_origin + "&" + str_dest + "&" + sensor + "&" + mode;
// Output format
String output = "json";
// Building the url to the web service
String url = "https://maps.googleapis.com/maps/api/directions/" + output + "?" + parameters;
return url;
}
private String downloadUrl(String strUrl) throws IOException {
String data = "";
InputStream iStream = null;
HttpURLConnection urlConnection = null;
try {
URL url = new URL(strUrl);
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", e.toString());
} finally {
iStream.close();
urlConnection.disconnect();
}
return data;
}
}
We’ve called an onMapClickListener
on the google map object. It’s used to set a marker on the clicked location and store that location in an ArrayList. The ArrayList is used to store the source and destination markers only. The getDirectionsUrl()
is called the Directions API URL with the output and parameters as shown below. "https://maps.googleapis.com/maps/api/directions/" + output + "?" + parameters;
The output variable holds a “json” string and the parameter string is created as: String parameters = str_origin + "&" + str_dest + "&" + sensor + "&" + mode;
We’ve set the mode=driving in the current application. The other modes of transport are:
The output of the application is given below: This brings an end to this tutorial. You can download the final project from the link below, add your own Google Map API key.
Thanks for learning with the DigitalOcean Community. Check out our offerings for compute, storage, networking, and managed databases.
the for loop in onPostExecute isnt getting executed. Please tell me how.
- Anirudh Kaluri
Every thing is great, but it doesnt zooms at current location… How to do that?? Please reply ASAP !
- kana
Hello. thx for your great post. How can i add more than one location and add polyline for it ?
- Amin
Replying to JournalDev
sir,did you got the solution for adding more than one marker
- harshit
i found error here, Error:Execution failed for task ‘:app:transformClassesWithDexForDebug’. > com.android.build.api.transform.TransformException: com.android.ide.common.process.ProcessException: java.util.concurrent.ExecutionException: com.android.dex.DexIndexOverflowException: method ID not in [0, 0xffff]: 65536 what must i do …?
- fajarra
Cant see a directional route between my marker points…getting a straight line instead… Please help me fix the issue
- Sjhivani
i am here just to say i love it, work on the first time is there any way to get the distance from the route?
- LeizaR
if i can 8 or 9 time in add point in polylineoption then give error you can try first get spinner and add 2 value driving and walking that add in mode value after select to change route that selection 7 or 8 time i sure give the error
- kritesh kabariya
Hi, you are really helped me, but I’m getting errors: java.lang.NullPointerException: PolylineOptions cannot be null. why is this error?
- Alexander
Morning when i run the app it crashes and the error points to this String str_dest = “destination=” + dest.latitude + “,” + dest.longitude;
- Gift
Hi Anupam Chugh, Could you tell me after drawing a map between two locations,how to update a user position with respect to his moment? Can you help me please… Thank you!
- Vinod Singh
I want to use this inside fragment. I did this in my OnCreateView()- View rootView=inflater.inflate(R.layout.image1,container,false); mapFragment = (SupportMapFragment) getFragmentManager().findFragmentById(R.id.map); mapFragment.getMapAsync(this); return rootView; And I am getting this error- java.lang.NullPointerException: Attempt to invoke virtual method ‘void com.google.android.gms.maps.SupportMapFragment.getMapAsync(com.google.android.gms.maps.OnMapReadyCallback)’ on a null object reference
- Bhavya Shah
Any help with this? java.lang.NullPointerException: PolylineOptions cannot be null. at com.google.maps.api.android.lib6.common.n.a(:com.google.android.gms.dynamite_mapsdynamite@13280052@13.2.80 (040700-211705629):32) at com.google.maps.api.android.lib6.impl.dm.(:com.google.android.gms.dynamite_mapsdynamite@13280052@13.2.80 (040700-211705629):6) at com.google.maps.api.android.lib6.impl.bc.a(:com.google.android.gms.dynamite_mapsdynamite@13280052@13.2.80 (040700-211705629):80) at com.google.android.gms.maps.internal.l.a(:com.google.android.gms.dynamite_mapsdynamite@13280052@13.2.80 (040700-211705629):501) at fh.onTransact(:com.google.android.gms.dynamite_mapsdynamite@13280052@13.2.80 (040700-211705629):10) at android.os.Binder.transact(Binder.java:667) at com.google.android.gms.internal.maps.zza.transactAndReadException(Unknown Source:7) at com.google.android.gms.maps.internal.zzg.addPolyline(Unknown Source:9) at com.google.android.gms.maps.GoogleMap.addPolyline(Unknown Source:4) at com.example.hb.navdrawerapp.SecondFragment$ParserTask.onPostExecute(SecondFragment.java:169) at com.example.hb.navdrawerapp.SecondFragment$ParserTask.onPostExecute(SecondFragment.java:121) at android.os.AsyncTask.finish(AsyncTask.java:695) at android.os.AsyncTask.access$600(AsyncTask.java:180) at android.os.AsyncTask$InternalHandler.handleMessage(AsyncTask.java:712) at android.os.Handler.dispatchMessage(Handler.java:106) at android.os.Looper.loop(Looper.java:193) at android.app.ActivityThread.main(ActivityThread.java:6669) at java.lang.reflect.Method.invoke(Native Method) at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:493) at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:858)
- Bhavya Shah
I want to draw route between more than two points. How can i do that ? Is it possible with a single call ?
- Syed Reazul Elahee
Dear I have gone through your tutorials of google map android. I am stuck to show journey route of train covered and remaining in two different colors. Second color overlapping on 1st one… 2nd issue it is showing alternative route which I coded alternatives=false also but still showing extra lines… Please visit URL to have more information about issue…https://stackoverflow.com/questions/57495955/how-to-show-journey-of-train-reached-and-remaining-on-mobile-app I want little help to sort these small issues…
- Vinod Kadiyan
I want to draw route between two points in map.But as per the above code I could only select two points in map, the direction doesn’t came. Is there any suggestions for me to solve .
- Prabeesh P
Hi , Im trying to understand your code since I am a beginner. Why do I keep getting this runtime error: java.lang.NullPointerException: Attempt to invoke interface method ‘int java.util.List.size()’ on a null object reference it has something to do with result being null
- Thomas Tsuma
Hey Anupam, I hope you will be fine. I have an issue in android related to maps. Can you help me?
- Ahmed Raza
Please refactor the code because we are facing a MAP API KEY issue so add this in your code so that we can save our time
- Nishit Gajjar
hello sir,i want to draw the route between two place from edit text which we enter pick location and drop location.How can i show this from edit text and draw route between two place?Please reply
- Sitansu
Hi Is it mandatory to add billing for Google api Am facing error on that
- Purushotham
i am facing this error… how to resolved please help of this { “error_message” : “You must enable Billing on the Google Cloud Project at https://console.cloud.google.com/project/\_/billing/enable Learn more at https://developers.google.com/maps/gmp-get-started”,
- khurseed ansari
Get paid to write technical tutorials and select a tech-focused charity to receive a matching donation.
Full documentation for every DigitalOcean product.
The Wave has everything you need to know about building a business, from raising funding to marketing your product.
Stay up to date by signing up for DigitalOcean’s Infrastructure as a Newsletter.
New accounts only. By submitting your email you agree to our Privacy Policy
Scale up as you grow — whether you're running one virtual machine or ten thousand.
Sign up and get $200 in credit for your first 60 days with DigitalOcean.*
*This promotional offer applies to new accounts only.