如何在Google Directions API(alternatives=true)中筛选多类型路线并修复代码
解决Google Directions API多路线筛选与显示问题
看起来你已经成功调用了带alternatives=true的Directions API,拿到了3条路线,但现有代码因为循环中重复覆盖PolylineOptions,最终只显示了最后一条路线。接下来我们一步步实现最快路线、最短路线、避收费路线的筛选功能,同时优化代码结构让它更易维护。
第一步:创建RouteModel封装路线信息
首先,我们创建一个数据类来封装每条路线的关键信息,避免用HashMap带来的混乱:
public class RouteModel { public String distanceText; public String durationText; public int distanceValue; // 距离数值(米),用于排序最短路线 public int durationValue; // 时长数值(秒),用于排序最快路线 public boolean hasTolls; // 是否包含收费路段 public List<LatLng> pathPoints; // 路线的所有坐标点 public RouteModel() { pathPoints = new ArrayList<>(); } }
第二步:修改DirectionsJSONParser解析完整路线信息
原来的Parser只提取了部分信息,现在我们要补充解析距离/时长的数值、是否收费(通过检查路线步骤中的toll_road字段):
public class DirectionsJSONParser { public List<RouteModel> parse(JSONObject jObject) { List<RouteModel> routeList = new ArrayList<>(); JSONArray jRoutes = null; JSONArray jLegs = null; JSONArray jSteps = null; try { jRoutes = jObject.getJSONArray("routes"); // 遍历每条路线 for (int i = 0; i < jRoutes.length(); i++) { RouteModel route = new RouteModel(); JSONObject jRoute = jRoutes.getJSONObject(i); jLegs = jRoute.getJSONArray("legs"); boolean hasTolls = false; // 遍历路线的每个Leg for (int j = 0; j < jLegs.length(); j++) { JSONObject jLeg = jLegs.getJSONObject(j); // 解析距离信息 JSONObject jDistance = jLeg.getJSONObject("distance"); route.distanceText = jDistance.getString("text"); route.distanceValue = jDistance.getInt("value"); // 解析时长信息 JSONObject jDuration = jLeg.getJSONObject("duration"); route.durationText = jDuration.getString("text"); route.durationValue = jDuration.getInt("value"); // 检查是否包含收费路段 jSteps = jLeg.getJSONArray("steps"); for (int k = 0; k < jSteps.length(); k++) { JSONObject jStep = jSteps.getJSONObject(k); if (jStep.has("toll_road") && jStep.getBoolean("toll_road")) { hasTolls = true; break; } } route.hasTolls = hasTolls; // 解析路线坐标点 for (int k = 0; k < jSteps.length(); k++) { JSONObject jStep = jSteps.getJSONObject(k); JSONObject polylineObj = jStep.getJSONObject("polyline"); String polyline = polylineObj.getString("points"); List<LatLng> points = decodePoly(polyline); route.pathPoints.addAll(points); } } routeList.add(route); } } catch (JSONException e) { e.printStackTrace(); } catch (Exception e) { e.printStackTrace(); } return routeList; } // 保留原来的decodePoly方法 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 point = new LatLng((double) lat / 1E5, (double) lng / 1E5); poly.add(point); } return poly; } }
第三步:修改AsyncTask处理解析结果
原来的AsyncTask返回的是List<List<HashMap>>,现在改成返回List<RouteModel>,并实现筛选逻辑:
// 修改AsyncTask的泛型参数 private class FetchDirectionsTask extends AsyncTask<String, Void, List<RouteModel>> { private List<RouteModel> routeList; // 保存路线列表用于UI切换 @Override protected List<RouteModel> doInBackground(String... strings) { JSONObject jsonObject; try { jsonObject = new JSONObject(strings[0]); DirectionsJSONParser directionsJSONParser = new DirectionsJSONParser(); routeList = directionsJSONParser.parse(jsonObject); } catch (JSONException e) { e.printStackTrace(); } return routeList; } @Override protected void onPostExecute(List<RouteModel> routes) { if (routes == null || routes.isEmpty()) { Toast.makeText(MapActivity.this, "Directions not found!", Toast.LENGTH_SHORT).show(); return; } routeList = routes; // 默认显示最快路线 displaySelectedRoute(getFastestRoute(routeList)); // 初始化UI按钮(可以放到Activity onCreate里) initRouteSwitchButtons(); } // 获取最快路线:时长数值最小的 private RouteModel getFastestRoute(List<RouteModel> routeList) { RouteModel fastest = routeList.get(0); for (RouteModel route : routeList) { if (route.durationValue < fastest.durationValue) { fastest = route; } } return fastest; } // 获取最短路线:距离数值最小的 private RouteModel getShortestRoute(List<RouteModel> routeList) { RouteModel shortest = routeList.get(0); for (RouteModel route : routeList) { if (route.distanceValue < shortest.distanceValue) { shortest = route; } } return shortest; } // 获取避收费路线:优先选最快的无收费路线,没有的话返回null private RouteModel getTollFreeRoute(List<RouteModel> routeList) { List<RouteModel> tollFreeRoutes = new ArrayList<>(); for (RouteModel route : routeList) { if (!route.hasTolls) { tollFreeRoutes.add(route); } } if (tollFreeRoutes.isEmpty()) { Toast.makeText(MapActivity.this, "No toll-free routes available!", Toast.LENGTH_SHORT).show(); return null; } return getFastestRoute(tollFreeRoutes); } // 绘制选中的路线 private void displaySelectedRoute(RouteModel route) { if (route == null) return; // 清除之前的路线,避免重叠 mMap.clear(); PolylineOptions polylineOptions = new PolylineOptions(); polylineOptions.addAll(route.pathPoints); polylineOptions.width(12); polylineOptions.color(Color.RED); polylineOptions.geodesic(true); mMap.addPolyline(polylineOptions); // 调整地图视野到路线范围 LatLngBounds.Builder boundsBuilder = new LatLngBounds.Builder(); for (LatLng point : route.pathPoints) { boundsBuilder.include(point); } LatLngBounds routeBounds = boundsBuilder.build(); mMap.animateCamera(CameraUpdateFactory.newLatLngBounds(routeBounds, 12)); // 更新距离和时长显示 mDisTextView.setText(route.distanceText); mDuraTextView.setText(route.durationText); } // 初始化路线切换按钮 private void initRouteSwitchButtons() { Button btnFastest = findViewById(R.id.btn_fastest); Button btnShortest = findViewById(R.id.btn_shortest); Button btnTollFree = findViewById(R.id.btn_toll_free); btnFastest.setOnClickListener(v -> displaySelectedRoute(getFastestRoute(routeList))); btnShortest.setOnClickListener(v -> displaySelectedRoute(getShortestRoute(routeList))); btnTollFree.setOnClickListener(v -> displaySelectedRoute(getTollFreeRoute(routeList))); } }
关键问题修复说明
- 原有代码只显示一条路线的原因:在
onPostExecute的循环中,每次都会重新创建polylineOptions和points,最后只添加了最后一次循环的Polyline,所以只显示最后一条路线。现在我们先筛选出目标路线,再单独绘制它。 - 筛选逻辑的核心:通过解析API返回的
distance.value(米)和duration.value(秒)来做数值比较,比文本更准确;通过检查步骤中的toll_road字段判断是否有收费路段。
内容的提问来源于stack exchange,提问作者Samuel Teo
相关产品推荐
相关产品推荐

