为什么使用KML数据检索Android版Google路线不再适用?

可能重复:
Google地图输出= kml破了?

几天后,我试图使用KML数据检索Google Directions,我开始遇到错误。 错误似乎是我请求的网址不再搜索KML数据,它返回整个页面。 为了实现这一目标,我遵循了这一点。

有什么解决方案呢? 有没有其他的选择?

更新:

由于现在使用Android Google Maps v2,因此需要对代码进行调整,才能在此处找到v2地图。


原始答案:

这种通过解析KML文件从Google提取Google路线的方式自2012年7月27日起不再可用(因为Google已经更改了检索Google Directions的结构,现在只能通过JSON或XML获取),现在是时候将您的代码迁移到JSON而不是KML。

我是通过创建6个类来完成的

Parser.java

public interface Parser { public Route parse(); } 

XMLParser.java

 public class XMLParser { // names of the XML tags protected static final String MARKERS = "markers"; protected static final String MARKER = "marker"; protected URL feedUrl; protected XMLParser(final String feedUrl) { try { this.feedUrl = new URL(feedUrl); } catch (MalformedURLException e) { //Log.e(e.getMessage(), "XML parser - " + feedUrl); } } protected InputStream getInputStream() { try { return feedUrl.openConnection().getInputStream(); } catch (IOException e) { //Log.e(e.getMessage(), "XML parser - " + feedUrl); return null; } } } 

Segment.java

 public class Segment { /** Points in this segment. **/ private GeoPoint start; /** Turn instruction to reach next segment. **/ private String instruction; /** Length of segment. **/ private int length; /** Distance covered. **/ private double distance; /** * Create an empty segment. */ public Segment() { } /** * Set the turn instruction. * @param turn Turn instruction string. */ public void setInstruction(final String turn) { this.instruction = turn; } /** * Get the turn instruction to reach next segment. * @return a String of the turn instruction. */ public String getInstruction() { return instruction; } /** * Add a point to this segment. * @param point GeoPoint to add. */ public void setPoint(final GeoPoint point) { start = point; } /** Get the starting point of this * segment. * @return a GeoPoint */ public GeoPoint startPoint() { return start; } /** Creates a segment which is a copy of this one. * @return a Segment that is a copy of this one. */ public Segment copy() { final Segment copy = new Segment(); copy.start = start; copy.instruction = instruction; copy.length = length; copy.distance = distance; return copy; } /** * @param length the length to set */ public void setLength(final int length) { this.length = length; } /** * @return the length */ public int getLength() { return length; } /** * @param distance the distance to set */ public void setDistance(double distance) { this.distance = distance; } /** * @return the distance */ public double getDistance() { return distance; } } 

Route.java

 public class Route { private String name; private final List<GeoPoint> points; private List<Segment> segments; private String copyright; private String warning; private String country; private int length; private String polyline; public Route() { points = new ArrayList<GeoPoint>(); segments = new ArrayList<Segment>(); } public void addPoint(final GeoPoint p) { points.add(p); } public void addPoints(final List<GeoPoint> points) { this.points.addAll(points); } public List<GeoPoint> getPoints() { return points; } public void addSegment(final Segment s) { segments.add(s); } public List<Segment> getSegments() { return segments; } /** * @param name the name to set */ public void setName(final String name) { this.name = name; } /** * @return the name */ public String getName() { return name; } /** * @param copyright the copyright to set */ public void setCopyright(String copyright) { this.copyright = copyright; } /** * @return the copyright */ public String getCopyright() { return copyright; } /** * @param warning the warning to set */ public void setWarning(String warning) { this.warning = warning; } /** * @return the warning */ public String getWarning() { return warning; } /** * @param country the country to set */ public void setCountry(String country) { this.country = country; } /** * @return the country */ public String getCountry() { return country; } /** * @param length the length to set */ public void setLength(int length) { this.length = length; } /** * @return the length */ public int getLength() { return length; } /** * @param polyline the polyline to set */ public void setPolyline(String polyline) { this.polyline = polyline; } /** * @return the polyline */ public String getPolyline() { return polyline; } } 

GoogleParser.java

 public class GoogleParser extends XMLParser implements Parser { /** Distance covered. **/ private int distance; public GoogleParser(String feedUrl) { super(feedUrl); } /** * Parses a url pointing to a Google JSON object to a Route object. * @return a Route object based on the JSON object. */ public Route parse() { // turn the stream into a string final String result = convertStreamToString(this.getInputStream()); //Create an empty route final Route route = new Route(); //Create an empty segment final Segment segment = new Segment(); try { //Tranform the string into a json object final JSONObject json = new JSONObject(result); //Get the route object final JSONObject jsonRoute = json.getJSONArray("routes").getJSONObject(0); //Get the leg, only one leg as we don't support waypoints final JSONObject leg = jsonRoute.getJSONArray("legs").getJSONObject(0); //Get the steps for this leg final JSONArray steps = leg.getJSONArray("steps"); //Number of steps for use in for loop final int numSteps = steps.length(); //Set the name of this route using the start & end addresses route.setName(leg.getString("start_address") + " to " + leg.getString("end_address")); //Get google's copyright notice (tos requirement) route.setCopyright(jsonRoute.getString("copyrights")); //Get the total length of the route. route.setLength(leg.getJSONObject("distance").getInt("value")); //Get any warnings provided (tos requirement) if (!jsonRoute.getJSONArray("warnings").isNull(0)) { route.setWarning(jsonRoute.getJSONArray("warnings").getString(0)); } /* Loop through the steps, creating a segment for each one and * decoding any polylines found as we go to add to the route object's * map array. Using an explicit for loop because it is faster! */ for (int i = 0; i < numSteps; i++) { //Get the individual step final JSONObject step = steps.getJSONObject(i); //Get the start position for this step and set it on the segment final JSONObject start = step.getJSONObject("start_location"); final GeoPoint position = new GeoPoint((int) (start.getDouble("lat")*1E6), (int) (start.getDouble("lng")*1E6)); segment.setPoint(position); //Set the length of this segment in metres final int length = step.getJSONObject("distance").getInt("value"); distance += length; segment.setLength(length); segment.setDistance(distance/1000); //Strip html from google directions and set as turn instruction segment.setInstruction(step.getString("html_instructions").replaceAll("<(.*?)*>", "")); //Retrieve & decode this segment's polyline and add it to the route. route.addPoints(decodePolyLine(step.getJSONObject("polyline").getString("points"))); //Push a copy of the segment to the route route.addSegment(segment.copy()); } } catch (JSONException e) { Log.e(e.getMessage(), "Google JSON Parser - " + feedUrl); } return route; } /** * Convert an inputstream to a string. * @param input inputstream to convert. * @return a String of the inputstream. */ private static String convertStreamToString(final InputStream input) { final BufferedReader reader = new BufferedReader(new InputStreamReader(input)); final StringBuilder sBuf = new StringBuilder(); String line = null; try { while ((line = reader.readLine()) != null) { sBuf.append(line); } } catch (IOException e) { Log.e(e.getMessage(), "Google parser, stream2string"); } finally { try { input.close(); } catch (IOException e) { Log.e(e.getMessage(), "Google parser, stream2string"); } } return sBuf.toString(); } /** * Decode a polyline string into a list of GeoPoints. * @param poly polyline encoded string to decode. * @return the list of GeoPoints represented by this polystring. */ private List<GeoPoint> decodePolyLine(final String poly) { int len = poly.length(); int index = 0; List<GeoPoint> decoded = new ArrayList<GeoPoint>(); int lat = 0; int lng = 0; while (index < len) { int b; int shift = 0; int result = 0; do { b = poly.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 = poly.charAt(index++) - 63; result |= (b & 0x1f) << shift; shift += 5; } while (b >= 0x20); int dlng = ((result & 1) != 0 ? ~(result >> 1) : (result >> 1)); lng += dlng; decoded.add(new GeoPoint( (int) (lat*1E6 / 1E5), (int) (lng*1E6 / 1E5))); } return decoded; } } 

RouteOverlay.java

 public class RouteOverlay extends Overlay { /** GeoPoints representing this routePoints. **/ private final List<GeoPoint> routePoints; /** Colour to paint routePoints. **/ private int colour; /** Alpha setting for route overlay. **/ private static final int ALPHA = 120; /** Stroke width. **/ private static final float STROKE = 4.5f; /** Route path. **/ private final Path path; /** Point to draw with. **/ private final Point p; /** Paint for path. **/ private final Paint paint; /** * Public constructor. * * @param route Route object representing the route. * @param defaultColour default colour to draw route in. */ public RouteOverlay(final Route route, final int defaultColour) { super(); routePoints = route.getPoints(); colour = defaultColour; path = new Path(); p = new Point(); paint = new Paint(); } @Override public final void draw(final Canvas c, final MapView mv, final boolean shadow) { super.draw(c, mv, shadow); paint.setColor(colour); paint.setAlpha(ALPHA); paint.setAntiAlias(true); paint.setStrokeWidth(STROKE); paint.setStyle(Paint.Style.STROKE); redrawPath(mv); c.drawPath(path, paint); } /** * Set the colour to draw this route's overlay with. * * @param c Int representing colour. */ public final void setColour(final int c) { colour = c; } /** * Clear the route overlay. */ public final void clear() { routePoints.clear(); } /** * Recalculate the path accounting for changes to * the projection and routePoints. * @param mv MapView the path is drawn to. */ private void redrawPath(final MapView mv) { final Projection prj = mv.getProjection(); path.rewind(); final Iterator<GeoPoint> it = routePoints.iterator(); prj.toPixels(it.next(), p); path.moveTo(px, py); while (it.hasNext()) { prj.toPixels(it.next(), p); path.lineTo(px, py); } path.setLastPoint(px, py); } } 

然后在包含Map的Activity中执行此操作:

1 – 添加此功能:

 private Route directions(final GeoPoint start, final GeoPoint dest) { Parser parser; //https://developers.google.com/maps/documentation/directions/#JSON <- get api String jsonURL = "http://maps.googleapis.com/maps/api/directions/json?"; final StringBuffer sBuf = new StringBuffer(jsonURL); sBuf.append("origin="); sBuf.append(start.getLatitudeE6()/1E6); sBuf.append(','); sBuf.append(start.getLongitudeE6()/1E6); sBuf.append("&destination="); sBuf.append(dest.getLatitudeE6()/1E6); sBuf.append(','); sBuf.append(dest.getLongitudeE6()/1E6); sBuf.append("&sensor=true&mode=driving"); parser = new GoogleParser(sBuf.toString()); Route r = parser.parse(); return r; } 

2-在onCreate()函数中添加这个:

 MapView mapView = (MapView) findViewById(R.id.mapview); //or you can declare it directly with the API key Route route = directions(new GeoPoint((int)(26.2*1E6),(int)(50.6*1E6)), new GeoPoint((int)(26.3*1E6),(int)(50.7*1E6))); RouteOverlay routeOverlay = new RouteOverlay(route, Color.BLUE); mapView.getOverlays().add(routeOverlay); mapView.invalidate(); 

编辑:如果您遇到异常,请使用AsyncTask中的directions()函数以避免在UI线程上进行网络处理。