How to draw interactive Polyline on route google maps v2 android

AndroidGoogle MapsGoogle Maps-Android-Api-2

Android Problem Overview


i have the following code which is drawing polylines for me and working fine, But the problem is that its not drawing interactive polylines, drawn lines are missing some pixels !

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.UnsupportedEncodingException;
import java.util.ArrayList;
import java.util.List;

import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.impl.client.DefaultHttpClient;
import org.json.JSONArray;
import org.json.JSONObject;

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.BitmapDescriptorFactory;
import com.google.android.gms.maps.model.LatLng;
import com.google.android.gms.maps.model.MarkerOptions;
import com.google.android.gms.maps.model.Polyline;
import com.google.android.gms.maps.model.PolylineOptions;

import android.app.ProgressDialog;
import android.content.Context;
import android.graphics.Color;
import android.os.AsyncTask;
import android.os.Bundle;
import android.support.v4.app.FragmentActivity;
import android.util.Log;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;

public class testRoute extends FragmentActivity implements OnClickListener {

	private GoogleMap myMap;
	Polyline line;
	Context context;

	// Static LatLng
	LatLng startLatLng = new LatLng(30.707104, 76.690749);
	LatLng endLatLng = new LatLng(30.721419, 76.730017);

	public void onCreate(Bundle bd) {
		super.onCreate(bd);
		setContentView(R.layout.passanger_home_call);
		context = testRoute.this;

		// Temp GetTrails Button
		Button btntemp = (Button) findViewById(R.id.btn_pass_home_call_temp);
		btntemp.setOnClickListener(this);

		// GoogleMap myMap
		myMap = ((SupportMapFragment) getSupportFragmentManager()
				.findFragmentById(R.id.map_pass_home_call)).getMap();
		myMap.setMyLocationEnabled(true);
		myMap.moveCamera(CameraUpdateFactory.newLatLng(startLatLng));
		myMap.animateCamera(CameraUpdateFactory.zoomTo(12));

		// Now auto clicking the button
		btntemp.performClick();
	}

	@Override
	public void onClick(View v) {

		switch (v.getId()) {
		case R.id.btn_pass_home_call_temp:
			String urlTopass = makeURL(startLatLng.latitude,
					startLatLng.longitude, endLatLng.latitude,
					endLatLng.longitude);
			new connectAsyncTask(urlTopass).execute();
			break;

		default:
			break;
		}

	}

	private class connectAsyncTask extends AsyncTask<Void, Void, String> {
		private ProgressDialog progressDialog;
		String url;

		connectAsyncTask(String urlPass) {
			url = urlPass;
		}

		@Override
		protected void onPreExecute() {
			// TODO Auto-generated method stub
			super.onPreExecute();
			progressDialog = new ProgressDialog(context);
			progressDialog.setMessage("Fetching route, Please wait...");
			progressDialog.setIndeterminate(true);
			progressDialog.show();
		}

		@Override
		protected String doInBackground(Void... params) {
			JSONParser jParser = new JSONParser();
			String json = jParser.getJSONFromUrl(url);
			return json;
		}

		@Override
		protected void onPostExecute(String result) {
			super.onPostExecute(result);
			progressDialog.hide();
			if (result != null) {
				drawPath(result);
			}
		}
	}

	public String makeURL(double sourcelat, double sourcelog, double destlat,
			double destlog) {
		StringBuilder urlString = new StringBuilder();
		urlString.append("http://maps.googleapis.com/maps/api/directions/json");
		urlString.append("?origin=");// from
		urlString.append(Double.toString(sourcelat));
		urlString.append(",");
		urlString.append(Double.toString(sourcelog));
		urlString.append("&destination=");// to
		urlString.append(Double.toString(destlat));
		urlString.append(",");
		urlString.append(Double.toString(destlog));
		urlString.append("&sensor=false&mode=driving&alternatives=true");
		return urlString.toString();
	}

	public class JSONParser {

		InputStream is = null;
		JSONObject jObj = null;
		String json = "";

		// constructor
		public JSONParser() {
		}

		public String getJSONFromUrl(String url) {

			// Making HTTP request
			try {
				// defaultHttpClient
				DefaultHttpClient httpClient = new DefaultHttpClient();
				HttpPost httpPost = new HttpPost(url);

				HttpResponse httpResponse = httpClient.execute(httpPost);
				HttpEntity httpEntity = httpResponse.getEntity();
				is = httpEntity.getContent();

			} catch (UnsupportedEncodingException e) {
				e.printStackTrace();
			} catch (ClientProtocolException e) {
				e.printStackTrace();
			} catch (IOException e) {
				e.printStackTrace();
			}
			try {
				BufferedReader reader = new BufferedReader(
						new InputStreamReader(is, "iso-8859-1"), 8);
				StringBuilder sb = new StringBuilder();
				String line = null;
				while ((line = reader.readLine()) != null) {
					sb.append(line + "\n");
				}

				json = sb.toString();
				is.close();
			} catch (Exception e) {
				Log.e("Buffer Error", "Error converting result " + e.toString());
			}
			return json;

		}
	}

	public void drawPath(String result) {
		if (line != null) {
			myMap.clear();
		}
		myMap.addMarker(new MarkerOptions().position(endLatLng).icon(
				BitmapDescriptorFactory.fromResource(R.drawable.redpin_marker)));
		myMap.addMarker(new MarkerOptions().position(startLatLng).icon(
				BitmapDescriptorFactory.fromResource(R.drawable.redpin_marker)));
		try {
			// Tranform the string into a json object
			final JSONObject json = new JSONObject(result);
			JSONArray routeArray = json.getJSONArray("routes");
			JSONObject routes = routeArray.getJSONObject(0);
			JSONObject overviewPolylines = routes
					.getJSONObject("overview_polyline");
			String encodedString = overviewPolylines.getString("points");
			List<LatLng> list = decodePoly(encodedString);

			for (int z = 0; z < list.size() - 1; z++) {
				LatLng src = list.get(z);
				LatLng dest = list.get(z + 1);
				line = myMap.addPolyline(new PolylineOptions()
						.add(new LatLng(src.latitude, src.longitude),
								new LatLng(dest.latitude, dest.longitude))
						.width(5).color(Color.BLUE).geodesic(true));
			}

		} catch (Exception e) {
			e.printStackTrace();
		}
	}

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

Code is Working fine And Drawing Route from one place to another but not drawing the interactive Routes

Screent Shot :- enter image description here

I think problem is with my drawPath() method :

public void drawPath(String result) {
		if (line != null) {
			myMap.clear();
		}
		myMap.addMarker(new MarkerOptions().position(endLatLng).icon(
				BitmapDescriptorFactory.fromResource(R.drawable.redpin_marker)));
		myMap.addMarker(new MarkerOptions().position(startLatLng).icon(
				BitmapDescriptorFactory.fromResource(R.drawable.redpin_marker)));
		try {
			// Tranform the string into a json object
			final JSONObject json = new JSONObject(result);
			JSONArray routeArray = json.getJSONArray("routes");
			JSONObject routes = routeArray.getJSONObject(0);
			JSONObject overviewPolylines = routes
					.getJSONObject("overview_polyline");
			String encodedString = overviewPolylines.getString("points");
			List<LatLng> list = decodePoly(encodedString);

			for (int z = 0; z < list.size() - 1; z++) {
				LatLng src = list.get(z);
				LatLng dest = list.get(z + 1);
				line = myMap.addPolyline(new PolylineOptions()
						.add(new LatLng(src.latitude, src.longitude),
								new LatLng(dest.latitude, dest.longitude))
						.width(5).color(Color.BLUE).geodesic(true));
			}

		} catch (Exception e) {
			e.printStackTrace();
		}
	}

Ignore The markers just suggest me about adding interactive polyline?

Android Solutions


Solution 1 - Android

Instead of creating too many short Polylines just create one like here:

PolylineOptions options = new PolylineOptions().width(5).color(Color.BLUE).geodesic(true);
for (int z = 0; z < list.size(); z++) {
    LatLng point = list.get(z);
    options.add(point);
}
line = myMap.addPolyline(options);

I'm also not sure you should use geodesic when your points are so close to each other.

Solution 2 - Android

I've created a couple of map tutorials that will cover what you need

Animating the map describes howto create polylines based on a set of LatLngs. Using Google APIs on your map : Directions and Places describes howto use the Directions API and animate a marker along the path.

Take a look at these 2 tutorials and the Github project containing the sample app.

It contains some tips to make your code cleaner and more efficient:

  • Using Google HTTP Library for more efficient API access and easy JSON handling.

  • Using google-map-utils library for maps-related functions (like decoding the polylines)

  • Animating markers

Solution 3 - Android

You can use this method to draw polyline on googleMap

// Draw polyline on map
public void drawPolyLineOnMap(List<LatLng> list) {
    PolylineOptions polyOptions = new PolylineOptions();
    polyOptions.color(Color.RED);
    polyOptions.width(5);
    polyOptions.addAll(list);

    googleMap.clear();
    googleMap.addPolyline(polyOptions);

    LatLngBounds.Builder builder = new LatLngBounds.Builder();
    for (LatLng latLng : list) {
        builder.include(latLng);
    }

    final LatLngBounds bounds = builder.build();

    //BOUND_PADDING is an int to specify padding of bound.. try 100.
    CameraUpdate cu = CameraUpdateFactory.newLatLngBounds(bounds, BOUND_PADDING);
    googleMap.animateCamera(cu);
}

You need to add this line in your gradle in case you haven't.

compile 'com.google.android.gms:play-services-maps:8.4.0'

Solution 4 - Android

You should use options.addAll(allPoints); instead of options.add(point);

Solution 5 - Android

Using the google maps projection api to draw the polylines on an overlay view enables us to do a lot of things. Check this repo that has an example.

enter image description here

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionTarsem SinghView Question on Stackoverflow
Solution 1 - AndroidMaciejGórskiView Answer on Stackoverflow
Solution 2 - AndroidddewaeleView Answer on Stackoverflow
Solution 3 - AndroidAbhishekView Answer on Stackoverflow
Solution 4 - AndroideggcakerView Answer on Stackoverflow
Solution 5 - AndroidamalBitView Answer on Stackoverflow