使用 GoogleMaps Android API v2绘制两点之间的路径

Google 更改了 Android 的地图 API,并引入了 API V2。以前的绘图路径代码不能与 API V2一起使用。

我已经设法用 API V2绘制了一条路径。我找了很多解决办法,但是没有找到任何答案。所以我要分享它的答案。

105705 次浏览

首先,我们将得到来源和目的地点之间,我们必须绘制路线。然后我们将这些属性传递给下面的函数。

 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");
urlString.append("&key=YOUR_API_KEY");
return urlString.toString();
}

这个函数将使我们将要发送的 URL 得到 DirectionAPI 响应。然后我们将解析这个响应。解析器类是

public class JSONParser {


static InputStream is = null;
static JSONObject jObj = null;
static 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;


}
}

这个解析器将返回字符串。

JSONParser jParser = new JSONParser();
String json = jParser.getJSONFromUrl(url);

现在,我们将这个字符串发送到我们的绘图路径函数

public void drawPath(String  result) {


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);
Polyline line = mMap.addPolyline(new PolylineOptions()
.addAll(list)
.width(12)
.color(Color.parseColor("#05b1fb"))//Google maps blue color
.geodesic(true)
);
/*
for(int z = 0; z<list.size()-1;z++){
LatLng src= list.get(z);
LatLng dest= list.get(z+1);
Polyline line = mMap.addPolyline(new PolylineOptions()
.add(new LatLng(src.latitude, src.longitude), new LatLng(dest.latitude,   dest.longitude))
.width(2)
.color(Color.BLUE).geodesic(true));
}
*/
}
catch (JSONException e) {


}
}

上面的代码将在 mMap 上绘制路径

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

由于方向调用可能需要时间,因此我们将在异步任务中完成所有这些操作。 我的异步任务是

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(MainActivity.this);
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);
}
}
}

希望能有所帮助。

不知道我是否应该把这个作为答案或不..。

I used @Zeeshan0026's solution to draw the path...and the problem was that if I draw path once, and then I do try to draw path once again, both two paths show and this continues...paths showing even when markers were deleted... while, ideally, old paths' shouldn't be there once new path is drawn / markers are deleted..

通过一些其他的问题,我得到了下面的解决方案

我在 Zeeshan 的类中添加了以下函数

 public void clearRoute(){


for(Polyline line1 : polylines)
{
line1.remove();
}


polylines.clear();


}

在我的地图活动中,在绘制路径之前,我调用了这个函数

private Route rt;


rt.clearRoute();


if (src == null) {
Toast.makeText(getApplicationContext(), "Please select your Source", Toast.LENGTH_LONG).show();
}else if (Destination == null) {
Toast.makeText(getApplicationContext(), "Please select your Destination", Toast.LENGTH_LONG).show();
}else if (src.equals(Destination)) {
Toast.makeText(getApplicationContext(), "Source and Destinatin can not be the same..", Toast.LENGTH_LONG).show();
}else{


rt.drawRoute(mMap, MapsMainActivity.this, src,
Destination, false, "en");
}

你可以按照你的要求使用 rt.clearRoute();。 希望它将节省别人的几分钟,并将帮助一些初学者解决这个问题。

完整的类代码

Github

编辑: 这是维护活动的一部分代码。

case R.id.mkrbtn_set_dest:
Destination = selmarker.getPosition();
destmarker = selmarker;
desShape = createRouteCircle(Destination, false);


if (src == null) {
Toast.makeText(getApplicationContext(),
"Please select your Source first...",
Toast.LENGTH_LONG).show();
} else if (src.equals(Destination)) {
Toast.makeText(getApplicationContext(),
"Source and Destinatin can not be the same..",
Toast.LENGTH_LONG).show();
} else {


if (isNetworkAvailable()) {
rt.drawRoute(mMap, MapsMainActivity.this, src,
Destination, false, "en");
src = null;
Destination = null;


} else {
Toast.makeText(
getApplicationContext(),
"Internet Connection seems to be OFFLINE...!",
Toast.LENGTH_LONG).show();


}


}


break;

编辑2 根据评论

用途:

//variables as data members
GoogleMap mMap;
private Route rt;
static LatLng src;
static LatLng Destination;
//MapsMainActivity is my activity
//false for interim stops for traffic, google
// en language for html description returned


rt.drawRoute(mMap, MapsMainActivity.this, src,
Destination, false, "en");

在下面的代码中间点列表是一个路径点的数组列表

private String getMapsApiDirectionsUrl(GoogleMap googleMap, LatLng startLatLng, LatLng endLatLng, ArrayList<LatLng> midpointsList) {
String origin = "origin=" + startLatLng.latitude + "," + startLatLng.longitude;


String midpoints = "";
for (int mid = 0; mid < midpointsList.size(); mid++) {
midpoints += "|" + midpointsList.get(mid).latitude + "," + midpointsList.get(mid).longitude;
}


String waypoints = "waypoints=optimize:true" + midpoints + "|";


String destination = "destination=" + endLatLng.latitude + "," + endLatLng.longitude;
String key = "key=AIzaSyCV1sOa_7vASRBs6S3S6t1KofFvDhjohvI";


String sensor = "sensor=false";
String params = origin + "&" + waypoints + "&" + destination + "&" + sensor + "&" + key;
String output = "json";
String url = "https://maps.googleapis.com/maps/api/directions/" + output + "?" + params;




Log.e("url", url);
parseDirectionApidata(url, googleMap);
return url;
}

然后复制并粘贴这个网址到浏览器中进行检查,下面的代码是解析这个网址

    private void parseDirectionApidata(String url, final GoogleMap googleMap) {


final JSONObject jsonObject = new JSONObject();


try {


AppUtill.getJsonWithHTTPPost(ViewMapActivity.this, 1, new ServiceCallBack() {
@Override
public void serviceCallBack(int id, JSONObject jsonResult) throws JSONException {


if (jsonResult != null) {


Log.e("jsonRes", jsonResult.toString());


String status = jsonResult.optString("status");


if (status.equalsIgnoreCase("ok")) {
drawPath(jsonResult, googleMap);
}


} else {


Toast.makeText(ViewMapActivity.this, "Unable to parse Directions Data", Toast.LENGTH_LONG).show();
}


}
}, url, jsonObject);


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


}
}

然后将结果传递给 draPath 方法

    public void drawPath(JSONObject jObject, GoogleMap googleMap) {


List<List<HashMap<String, String>>> routes = new ArrayList<List<HashMap<String, String>>>();
JSONArray jRoutes = null;
JSONArray jLegs = null;
JSONArray jSteps = null;
List<LatLng> list = null;
try {


Toast.makeText(ViewMapActivity.this, "Drawing Path...", Toast.LENGTH_SHORT).show();
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<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 = decodePoly(polyline);
}
Log.e("list", list.toString());
routes.add(path);
Log.e("routes", routes.toString());
if (list != null) {
Polyline line = googleMap.addPolyline(new PolylineOptions()
.addAll(list)
.width(12)
.color(Color.parseColor("#FF0000"))//Google maps blue color #05b1fb
.geodesic(true)
);
}
}
}
} catch (JSONException 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;
}

解码多边形函数是解码由 Directions API 以编码形式提供的点(lat 和 long)

尝试下面两点之间的 用动画绘制路径得到时间和距离的解决方案。

Java

public class DirectionHelper {


public List<List<HashMap<String, String>>> parse(JSONObject jObject) {


List<List<HashMap<String, String>>> routes = new ArrayList<>();
JSONArray jRoutes;
JSONArray jLegs;
JSONArray jSteps;
JSONObject jDistance = null;
JSONObject jDuration = 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 path = new ArrayList<>();


/** Traversing all legs */
for (int j = 0; j < jLegs.length(); j++) {


/** Getting distance from the json data */
jDistance = ((JSONObject) jLegs.get(j)).getJSONObject("distance");
HashMap<String, String> hmDistance = new HashMap<String, String>();
hmDistance.put("distance", jDistance.getString("text"));


/** Getting duration from the json data */
jDuration = ((JSONObject) jLegs.get(j)).getJSONObject("duration");
HashMap<String, String> hmDuration = new HashMap<String, String>();
hmDuration.put("duration", jDuration.getString("text"));


/** Adding distance object to the path */
path.add(hmDistance);


/** Adding duration object to the path */
path.add(hmDuration);


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

获取 PathFromLocation.java

public class GetPathFromLocation extends AsyncTask<String, Void, List<List<HashMap<String, String>>>> {


private Context context;
private String TAG = "GetPathFromLocation";
private LatLng source, destination;
private ArrayList<LatLng> wayPoint;
private GoogleMap mMap;
private boolean animatePath, repeatDrawingPath;
private DirectionPointListener resultCallback;
private ProgressDialog progressDialog;


//https://www.mytrendin.com/draw-route-two-locations-google-maps-android/
//https://www.androidtutorialpoint.com/intermediate/google-maps-draw-path-two-points-using-google-directions-google-map-android-api-v2/


public GetPathFromLocation(Context context, LatLng source, LatLng destination, ArrayList<LatLng> wayPoint, GoogleMap mMap, boolean animatePath, boolean repeatDrawingPath, DirectionPointListener resultCallback) {
this.context = context;
this.source = source;
this.destination = destination;
this.wayPoint = wayPoint;
this.mMap = mMap;
this.animatePath = animatePath;
this.repeatDrawingPath = repeatDrawingPath;
this.resultCallback = resultCallback;
}


synchronized public String getUrl(LatLng source, LatLng dest, ArrayList<LatLng> wayPoint) {


String url = "https://maps.googleapis.com/maps/api/directions/json?sensor=false&mode=driving&origin="
+ source.latitude + "," + source.longitude + "&destination=" + dest.latitude + "," + dest.longitude;
for (int centerPoint = 0; centerPoint < wayPoint.size(); centerPoint++) {
if (centerPoint == 0) {
url = url + "&waypoints=optimize:true|" + wayPoint.get(centerPoint).latitude + "," + wayPoint.get(centerPoint).longitude;
} else {
url = url + "|" + wayPoint.get(centerPoint).latitude + "," + wayPoint.get(centerPoint).longitude;
}
}
url = url + "&key=" + context.getResources().getString(R.string.google_api_key);


return url;
}


public int getRandomColor() {
Random rnd = new Random();
return Color.argb(255, rnd.nextInt(256), rnd.nextInt(256), rnd.nextInt(256));
}


@Override
protected void onPreExecute() {
super.onPreExecute();
progressDialog = new ProgressDialog(context);
progressDialog.setMessage("Please wait...");
progressDialog.setIndeterminate(false);
progressDialog.setCancelable(false);
progressDialog.show();
}


@Override
protected List<List<HashMap<String, String>>> doInBackground(String... url) {


String data;


try {
InputStream inputStream = null;
HttpURLConnection connection = null;
try {
URL directionUrl = new URL(getUrl(source, destination, wayPoint));
connection = (HttpURLConnection) directionUrl.openConnection();
connection.connect();
inputStream = connection.getInputStream();


BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream));
StringBuffer stringBuffer = new StringBuffer();


String line = "";
while ((line = bufferedReader.readLine()) != null) {
stringBuffer.append(line);
}


data = stringBuffer.toString();
bufferedReader.close();


} catch (Exception e) {
Log.e(TAG, "Exception : " + e.toString());
return null;
} finally {
inputStream.close();
connection.disconnect();
}
Log.e(TAG, "Background Task data : " + data);


//Second AsyncTask


JSONObject jsonObject;
List<List<HashMap<String, String>>> routes = null;


try {
jsonObject = new JSONObject(data);
// Starts parsing data
DirectionHelper helper = new DirectionHelper();
routes = helper.parse(jsonObject);
Log.e(TAG, "Executing Routes : "/*, routes.toString()*/);


return routes;


} catch (Exception e) {
Log.e(TAG, "Exception in Executing Routes : " + e.toString());
return null;
}


} catch (Exception e) {
Log.e(TAG, "Background Task Exception : " + e.toString());
return null;
}
}


@Override
protected void onPostExecute(List<List<HashMap<String, String>>> result) {
super.onPostExecute(result);


if (progressDialog.isShowing()) {
progressDialog.dismiss();
}


ArrayList<LatLng> points;
PolylineOptions lineOptions = null;
String distance = "";
String duration = "";


// 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);


if (j == 0) {    // Get distance from the list
distance = (String) point.get("distance");
continue;
} else if (j == 1) { // Get duration from the list
duration = (String) point.get("duration");
continue;
}


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(8);
lineOptions.color(Color.RED);
//lineOptions.color(getRandomColor());


if (animatePath) {
final ArrayList<LatLng> finalPoints = points;
((AppCompatActivity) context).runOnUiThread(new Runnable() {
@Override
public void run() {
PolylineOptions polylineOptions;
final Polyline greyPolyLine, blackPolyline;
final ValueAnimator polylineAnimator;


LatLngBounds.Builder builder = new LatLngBounds.Builder();
for (LatLng latLng : finalPoints) {
builder.include(latLng);
}
polylineOptions = new PolylineOptions();
polylineOptions.color(Color.RED);
polylineOptions.width(8);
polylineOptions.startCap(new SquareCap());
polylineOptions.endCap(new SquareCap());
polylineOptions.jointType(ROUND);
polylineOptions.addAll(finalPoints);
greyPolyLine = mMap.addPolyline(polylineOptions);


polylineOptions = new PolylineOptions();
polylineOptions.width(8);
polylineOptions.color(Color.WHITE);
polylineOptions.startCap(new SquareCap());
polylineOptions.endCap(new SquareCap());
polylineOptions.zIndex(5f);
polylineOptions.jointType(ROUND);


blackPolyline = mMap.addPolyline(polylineOptions);
polylineAnimator = ValueAnimator.ofInt(0, 100);
polylineAnimator.setDuration(5000);
polylineAnimator.setInterpolator(new LinearInterpolator());
polylineAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator valueAnimator) {
List<LatLng> points = greyPolyLine.getPoints();
int percentValue = (int) valueAnimator.getAnimatedValue();
int size = points.size();
int newPoints = (int) (size * (percentValue / 100.0f));
List<LatLng> p = points.subList(0, newPoints);
blackPolyline.setPoints(p);
}
});


polylineAnimator.addListener(new Animator.AnimatorListener() {
@Override
public void onAnimationStart(Animator animation) {


}


@Override
public void onAnimationEnd(Animator animation) {
if (repeatDrawingPath) {
List<LatLng> greyLatLng = greyPolyLine.getPoints();
if (greyLatLng != null) {
greyLatLng.clear();


}
polylineAnimator.start();
}
}


@Override
public void onAnimationCancel(Animator animation) {
polylineAnimator.cancel();
}


@Override
public void onAnimationRepeat(Animator animation) {
}
});
polylineAnimator.start();
}
});
}


Log.e(TAG, "PolylineOptions Decoded");
}


// Drawing polyline in the Google Map for the i-th route
if (resultCallback != null && lineOptions != null)
resultCallback.onPath(lineOptions, distance, duration);
}
}

DirectionPointListener

public interface DirectionPointListener {
public void onPath(PolylineOptions polyLine,String distance,String duration);
}

现在在活动中使用下面的代码绘制路径

private GoogleMap mMap;
private ArrayList<LatLng> wayPoint = new ArrayList<>();
private SupportMapFragment mapFragment;


mapFragment = (SupportMapFragment) getSupportFragmentManager().findFragmentById(R.id.map);
mapFragment.getMapAsync(this);


@Override
public void onMapReady(GoogleMap googleMap) {
mMap = googleMap;


mMap.setOnMapLoadedCallback(new GoogleMap.OnMapLoadedCallback() {
@Override
public void onMapLoaded() {
LatLngBounds.Builder builder = new LatLngBounds.Builder();


/*Add Source Marker*/
MarkerOptions markerOptions = new MarkerOptions();
markerOptions.position(source);
markerOptions.icon(BitmapDescriptorFactory.defaultMarker(BitmapDescriptorFactory.HUE_GREEN));
mMap.addMarker(markerOptions);
builder.include(source);


/*Add Destination Marker*/
markerOptions = new MarkerOptions();
markerOptions.position(destination);
markerOptions.icon(BitmapDescriptorFactory.defaultMarker(BitmapDescriptorFactory.HUE_RED));
mMap.addMarker(markerOptions);
builder.include(destination);


LatLngBounds bounds = builder.build();


int width = mapFragment.getView().getMeasuredWidth();
int height = mapFragment.getView().getMeasuredHeight();
int padding = (int) (width * 0.15); // offset from edges of the map 10% of screen


CameraUpdate cu = CameraUpdateFactory.newLatLngBounds(bounds, width, height, padding);


mMap.animateCamera(cu);


new GetPathFromLocation(context, source, destination, wayPoint, mMap, true, false, new DirectionPointListener() {
@Override
public void onPath(PolylineOptions polyLine, String distance, String duration) {
mMap.addPolyline(polyLine);
Log.e(TAG, "onPath :: Distance :: " + distance + " Duration :: " + duration);


binding.txtDistance.setText(String.format(" %s", distance));
binding.txtDuration.setText(String.format(" %s", duration));
}
}).execute();
}
});
}

输出

enter image description here