Fragment中Google Map同时显示当前位置与服务端站点问题排查
问题根因
这个需求完全可以实现,你现在看不到火车站点是代码存在多个逻辑错误,核心问题如下:
- 权限判断写反:
get_stations()里你写的是if(checkLocationPermission()) { 仅打印日志 } else { 才发起网络请求拉站点 },等于用户授权后根本不会执行拉取站点的逻辑,没权限的时候反而去发请求。 - 重复绑定地图回调:你在
getcurrentlocatiom()和get_stations()里各找了一次SupportMapFragment、各绑定了一次getMapAsync,同一个地图实例被重复初始化,回调执行顺序完全混乱。 - 错误清空地图:
onMapReady里加完当前位置标记后直接调用gMap.clear(),之前添加的所有标记、折线都会被直接清除。 - 无效重复请求:位置回调里每次收到位置更新都重新调用
get_stations(),无限重复发网络请求,还会重复添加标记。 - JSON解析逻辑残缺:解析站点响应时直接调用
stations.getString(),但没有遍历服务端返回的站点数组,解析直接抛异常中断。 - 初始化时序错误:
onCreateView里页面刚加载就同时调用定位、拉站点方法,这时候地图还没初始化完成、权限也可能没授予,调用必然出问题。
修改步骤
1. 统一地图初始化入口
删掉其他地方重复绑定地图的逻辑,只在视图加载时初始化一次地图:
@Override public View onCreateView(@NonNull @NotNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { View rootView = inflater.inflate(R.layout.fragment_maps_line, container, false); // 仅初始化一次地图,不要在其他方法里重复find Fragment绑定回调 SupportMapFragment mapFragment = (SupportMapFragment) getChildFragmentManager().findFragmentById(R.id.map); mapFragment.getMapAsync(this); return rootView; }
2. 修正onMapReady逻辑
去掉错误的clear操作,等地图加载完成、权限校验通过后,再执行开启定位、拉取站点的操作:
@SuppressLint("MissingPermission") @Override public void onMapReady(@NonNull GoogleMap googleMap) { gMap = googleMap; if(checkLocationPermission()){ gMap.setMyLocationEnabled(true); // 地图就绪+权限OK再拉站点,仅调用一次 get_stations(); startLocationUpdates(); } }
3. 重写get_stations()方法
把写反的权限判断改回来,补全JSON解析逻辑,不要重复绑定地图:
public void get_stations(){ if(gMap == null) return; // 修正权限判断:有权限才拉取数据 if(checkLocationPermission()) { List<LatLng> routeArray = new ArrayList<>(); JSONObject requestParam = new JSONObject(); String GET_STATIONS = "https://help.php"; try { requestParam.put("sid", sid_user); } catch (JSONException e) { e.printStackTrace(); } JsonObjectRequest req = new JsonObjectRequest( Request.Method.POST, GET_STATIONS, requestParam, response -> { try { // 补全站点数组遍历,数组key按你实际接口返回的字段修改 JSONArray stationsArray = response.getJSONArray("stations"); for (int i = 0; i < stationsArray.length(); i++) { JSONObject stations = stationsArray.getJSONObject(i); String name = stations.getString("sname"); String lat = stations.getString("lat"); String lon = stations.getString("lon"); // 补上你之前漏取的经度字段 // 用Double解析经纬度,避免Float精度损失导致位置偏移 LatLng latLng = new LatLng(Double.parseDouble(lat), Double.parseDouble(lon)); gMap.addMarker(new MarkerOptions().position(latLng).title("站点:" + name)); if (!routeArray.contains(latLng)) { routeArray.add(latLng); } } drawLine(routeArray); // 调整视角同时包含当前位置和所有站点,不要每次移动到单个站点 LatLngBounds.Builder builder = new LatLngBounds.Builder(); builder.include(new LatLng(latitude, longitude)); for (LatLng point : routeArray) { builder.include(point); } gMap.animateCamera(CameraUpdateFactory.newLatLngBounds(builder.build(), 120)); } catch (Exception e) { e.printStackTrace(); } }, error -> Log.e("StationFetch", "拉取站点失败", error) ); if(getActivity() != null) { MainActivity.requestQueue.add(req); } } }
4. 修正位置回调逻辑
删掉回调里重复调用get_stations()的代码,收到位置更新只刷新经纬度变量即可,避免无限发请求:
@Override public void onLocationResult(LocationResult locationResult) { if (locationResult == null) { Log.d("main_activiyt_maps", "location request is null"); return; } // 删掉此处的get_stations()调用 for (Location location : locationResult.getLocations()) { latitude = location.getLatitude(); longitude = location.getLongitude(); currentLocation = location; } }
5. 修正权限申请回调
权限通过后如果地图已经就绪,直接执行后续逻辑,不要重复初始化定位客户端:
@Override public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) { switch (requestCode) { case MY_PERMISSION_REQUEST_ACCESS_FINE_LOCATION: { if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) { if(gMap != null) { gMap.setMyLocationEnabled(true); get_stations(); startLocationUpdates(); } } break; } } }
6. 补全drawLine方法
之前的方法没有把点位添加到折线配置里,补上逻辑:
public void drawLine(List<LatLng> points) { if (points == null || points.size() < 2) { return; } gMap.addPolyline(new PolylineOptions().addAll(points).width(5).color(Color.RED)); }
额外优化建议
- 位置更新间隔1秒过于频繁,非导航场景建议改成10秒(10000ms),降低耗电。
- 所有调用
getActivity()、getContext()的地方加非空判断,避免Fragment销毁后触发空指针。 - 经纬度解析统一用
Double.parseDouble(),不要用Float,避免精度损失导致点位偏移。
内容的提问来源于stack exchange,提问作者Elly
相关产品推荐
相关产品推荐

