Android Google Maps显示用户定位与服务端站点问题修复
问题根因
你代码里存在多个直接导致启动崩溃、功能异常的核心问题:
FusedLocationProviderClient从未初始化,调用getLastLocation()时直接触发空指针- 位置权限逻辑不一致:申请权限用的请求码是
101,权限回调里判断的请求码是0,授权成功后不会自动触发位置获取 - 时序逻辑错误:
onCreateView里调用的fetchLocation()是异步操作,立刻同步执行getMapAsync时currentLocation大概率为null,直接调用currentLocation.getLatitude()触发空指针 - Fragment管理器用错:嵌套在当前Fragment里的
SupportMapFragment应该用getChildFragmentManager()查找,你在fetchLocation里用了getParentFragmentManager()找不到Map实例,还做了错误的类型强转(当前Fragment没实现OnMapReadyCallback接口,强转直接崩溃) - 地图操作顺序错误:刚添加完当前位置Marker就调用
mMap.clear(),直接把刚加的当前位置标记清掉 - 权限申请回调没有后续逻辑:用户同意权限后没有重新调用位置获取方法
- 经纬度解析用
Float.parseFloat会丢失精度,且循环内重复设置Polyline颜色、重复移动相机属于无效冗余操作
修复方案
- 在
onCreate生命周期里初始化位置客户端 - 统一权限请求码,修正权限回调逻辑,授权后重新拉取位置
- 调整地图加载时序:等位置获取成功后再触发地图加载,避免空指针
- 统一用
getChildFragmentManager()查找嵌套的MapFragment,去掉错误的类型强转 - 调整地图clear的时机:在添加所有标记之前调用clear,避免误删已添加的标记
- 经纬度解析改用
Double.parseDouble保证精度,把Polyline颜色设置、相机边界调整放到循环外执行 - 增加位置为null、权限被拒绝的兜底处理,避免直接崩溃
修复后完整代码
public class MapsLine extends Fragment { private String sid_user; private int did; GoogleMap map; // 统一权限请求码 private static final int REQUEST_LOCATION_PERMISSION = 101; Location currentLocation; FusedLocationProviderClient fusedLocationProviderClient; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); // 初始化位置服务客户端 fusedLocationProviderClient = LocationServices.getFusedLocationProviderClient(requireContext()); } @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { View rootView = inflater.inflate(R.layout.fragment_maps_line, container, false); // 先检查权限拉取位置,位置拿到后再加载地图 fetchLocation(); return rootView; } private void initMap() { // 用childFragmentManager查找嵌套的地图Fragment SupportMapFragment mapFragment = (SupportMapFragment) getChildFragmentManager().findFragmentById(R.id.map); if (mapFragment == null) return; mapFragment.getMapAsync(mMap -> { map = mMap; mMap.setMapType(GoogleMap.MAP_TYPE_NORMAL); // 先清空地图旧标记,再添加新内容 mMap.clear(); // 渲染当前位置标记 if (currentLocation != null) { LatLng currentLatLng = new LatLng(currentLocation.getLatitude(), currentLocation.getLongitude()); mMap.addMarker(new MarkerOptions().position(currentLatLng).title("我的位置")); mMap.animateCamera(CameraUpdateFactory.newLatLngZoom(currentLatLng, 10)); } // 拉取服务端站点数据 List<LatLng> routeArray = new ArrayList<>(); PolylineOptions polylineOptions = new PolylineOptions().color(Color.RED).width(8f); JSONObject requestParam = new JSONObject(); String GET_STATIONS = "https://helpme.php"; try { requestParam.put("did", did); } catch (JSONException e) { e.printStackTrace(); } JsonObjectRequest req = new JsonObjectRequest( Request.Method.POST, GET_STATIONS, requestParam, response -> { try { JSONArray stations_array = response.getJSONArray("stations"); Log.d("main_activity_sid_map", stations_array.toString()); Log.d("main_activity_sid_map", String.valueOf(stations_array.length())); LatLngBounds.Builder boundsBuilder = LatLngBounds.builder(); // 把当前位置加入边界计算,打开地图可同时看到当前位置和所有站点 if (currentLocation != null) { boundsBuilder.include(new LatLng(currentLocation.getLatitude(), currentLocation.getLongitude())); } for (int j = 0; j < stations_array.length(); j++) { JSONObject stations = stations_array.getJSONObject(j); String name = stations.getString("sname"); // 用double解析经纬度避免精度丢失 double lat = stations.getDouble("lat"); double lon = stations.getDouble("lon"); Log.d("main_activity_sid_map", name + " " + lat + " " + lon); LatLng stationLatLng = new LatLng(lat, lon); // 添加站点标记 mMap.addMarker(new MarkerOptions().position(stationLatLng).title(name)); // 加入路线点集合 if (!routeArray.contains(stationLatLng)) { routeArray.add(stationLatLng); boundsBuilder.include(stationLatLng); } } // 循环外统一绘制路线 if (!routeArray.isEmpty()) { polylineOptions.addAll(routeArray); mMap.addPolyline(polylineOptions); // 调整相机到包含所有点的合适范围 LatLngBounds bounds = boundsBuilder.build(); int padding = 120; mMap.animateCamera(CameraUpdateFactory.newLatLngBounds(bounds, padding)); } } catch (Exception e) { e.printStackTrace(); } }, Throwable::printStackTrace ); if (getActivity() != null) { Volley.newRequestQueue(requireContext()).add(req); } }); } private void fetchLocation() { if (ActivityCompat.checkSelfPermission(requireContext(), Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(requireContext(), Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) { // 统一权限请求码,同时申请精确定位和粗略定位权限 requestPermissions( new String[]{Manifest.permission.ACCESS_FINE_LOCATION, Manifest.permission.ACCESS_COARSE_LOCATION}, REQUEST_LOCATION_PERMISSION); return; } Task<Location> task = fusedLocationProviderClient.getLastLocation(); task.addOnSuccessListener(location -> { // 兜底处理:lastLocation为null时给默认坐标,避免空指针 if (location != null) { currentLocation = location; Toast.makeText(requireContext(), "定位成功:" + currentLocation.getLatitude() + "," + currentLocation.getLongitude(), Toast.LENGTH_SHORT).show(); } else { Toast.makeText(requireContext(), "获取历史位置失败,请开启定位后重试", Toast.LENGTH_SHORT).show(); // 默认坐标设为北京,可根据需求修改 currentLocation = new Location("default"); currentLocation.setLatitude(39.9042); currentLocation.setLongitude(116.4074); } // 位置获取完成后再初始化地图 initMap(); }).addOnFailureListener(e -> { e.printStackTrace(); // 定位失败也走默认逻辑加载地图 currentLocation = new Location("default"); currentLocation.setLatitude(39.9042); currentLocation.setLongitude(116.4074); initMap(); }); } @Override public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { super.onRequestPermissionsResult(requestCode, permissions, grantResults); if (requestCode == REQUEST_LOCATION_PERMISSION) { if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) { Log.d("Location", "定位权限已授予"); // 授权成功后重新拉取位置 fetchLocation(); } else { Log.d("Location", "定位权限被拒绝"); Toast.makeText(requireContext(), "需要定位权限才能展示当前位置", Toast.LENGTH_SHORT).show(); // 权限拒绝也加载地图,使用默认坐标 currentLocation = new Location("default"); currentLocation.setLatitude(39.9042); currentLocation.setLongitude(116.4074); initMap(); } } } }
配置检查项
- 确认
AndroidManifest.xml中已经添加必要权限:
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" /> <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" /> <uses-permission android:name="android.permission.INTERNET" />
- 确认布局文件
fragment_maps_line.xml中MapFragment的id为map,类型为SupportMapFragment - 确认项目中已经正确配置Google Maps API密钥,否则地图会显示黑屏
内容的提问来源于stack exchange,提问作者Elly
相关产品推荐
相关产品推荐

