解决GoogleMaps.setMyLocationEnabled缺失权限及定位不显示问题
setMyLocationEnabled标红及位置不显示问题 我来帮你一步步拆解并解决这两个问题,先从代码标红的问题入手,再搞定位置不显示的问题~
一、先解决map.setMyLocationEnabled(true);标红的问题
这个红色下划线本质是编译器检测到权限逻辑不完整——你现在的代码只判断了权限未授权就直接return,但没有处理"引导用户授权"的流程,而且Android 6.0+系统要求危险权限必须动态申请。
1. 先在AndroidManifest.xml中声明必要权限
打开你的清单文件,在<manifest>标签内添加以下内容:
<!-- 基础位置权限 --> <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" /> <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" /> <!-- Android 10+ 后台定位需要(如果你的应用需要后台获取位置) --> <uses-permission android:name="android.permission.ACCESS_BACKGROUND_LOCATION" /> <!-- 声明依赖GPS硬件(可选) --> <uses-feature android:name="android.hardware.location.gps" android:required="false" /> <!-- 配置Google Maps API Key --> <meta-data android:name="com.google.android.geo.API_KEY" android:value="你的Google Maps API Key" />
记得把你的Google Maps API Key替换成你在Google Cloud平台申请的有效Key。
2. 补充动态权限申请逻辑
修改onMapReady方法,当权限未授权时发起请求,而不是直接return:
@Override public void onMapReady(GoogleMap googleMap) { map = googleMap; // 检查位置权限 if (ActivityCompat.checkSelfPermission(mContext, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(mContext, Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) { // 发起权限请求,自定义请求码1001 requestPermissions(new String[]{Manifest.permission.ACCESS_FINE_LOCATION, Manifest.permission.ACCESS_COARSE_LOCATION}, 1001); return; } // 权限已授权,启用我的位置 map.setMyLocationEnabled(true); map.animateCamera(CameraUpdateFactory.zoomTo(15)); }
3. 处理权限请求结果
在Fragment中重写onRequestPermissionsResult方法,处理用户授权后的逻辑:
@Override public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { super.onRequestPermissionsResult(requestCode, permissions, grantResults); if (requestCode == 1001) { // 判断权限是否授权成功 boolean fineLocationGranted = grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED; boolean coarseLocationGranted = grantResults.length > 1 && grantResults[1] == PackageManager.PERMISSION_GRANTED; if (fineLocationGranted || coarseLocationGranted) { // 权限授权成功,重新启用我的位置 if (map != null) { try { map.setMyLocationEnabled(true); map.animateCamera(CameraUpdateFactory.zoomTo(15)); } catch (SecurityException e) { e.printStackTrace(); } } } else { // 用户拒绝权限,弹出提示说明必要性 Toast.makeText(mContext, "需要位置权限才能显示你的位置", Toast.LENGTH_SHORT).show(); } } }
做完这三步,setMyLocationEnabled的红色下划线应该就消失了——因为我们保证了只有在权限授权后才会调用该方法,编译器不会再提示权限风险。
二、解决位置未标记/不显示的问题
你代码里有updateCurrentLocationMarker方法,但没有触发它的逻辑:也就是没有主动获取设备当前位置的代码。我们用Google推荐的FusedLocationProviderClient来实现位置获取。
1. 添加位置服务依赖
在build.gradle(Module level)的dependencies中添加:
implementation 'com.google.android.gms:play-services-location:21.0.1'
版本号可以用最新的稳定版。
2. 初始化位置客户端并获取当前位置
在Fragment中添加相关变量和方法:
private FusedLocationProviderClient fusedLocationClient; @Override public void onActivityCreated(@Nullable Bundle savedInstanceState) { super.onActivityCreated(savedInstanceState); mContext = getActivity(); // 初始化FusedLocationProviderClient fusedLocationClient = LocationServices.getFusedLocationProviderClient(mContext); FragmentManager fm = getActivity().getSupportFragmentManager(); supportMapFragment = (SupportMapFragment) fm.findFragmentById(R.id.map_container); if (supportMapFragment == null) { supportMapFragment = SupportMapFragment.newInstance(); fm.beginTransaction().replace(R.id.map_container, supportMapFragment).commit(); } supportMapFragment.getMapAsync(this); } // 获取当前位置 private void getCurrentLocation() { if (ActivityCompat.checkSelfPermission(mContext, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(mContext, Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) { return; } fusedLocationClient.getLastLocation() .addOnSuccessListener(location -> { // 获取位置成功,更新标记 if (location != null) { updateCurrentLocationMarker(location); } else { // 如果获取不到历史位置,请求实时位置更新 requestLocationUpdates(); } }) .addOnFailureListener(e -> { e.printStackTrace(); Toast.makeText(mContext, "获取位置失败", Toast.LENGTH_SHORT).show(); }); } // 请求实时位置更新 private void requestLocationUpdates() { LocationRequest locationRequest = LocationRequest.create(); locationRequest.setInterval(10000); // 10秒更新一次 locationRequest.setFastestInterval(5000); // 最快5秒更新一次 locationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY); if (ActivityCompat.checkSelfPermission(mContext, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(mContext, Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) { return; } fusedLocationClient.requestLocationUpdates(locationRequest, locationCallback, Looper.getMainLooper()); } // 位置更新回调 private final LocationCallback locationCallback = new LocationCallback() { @Override public void onLocationResult(LocationResult locationResult) { super.onLocationResult(locationResult); if (locationResult != null && locationResult.getLocations().size() > 0) { int latestIndex = locationResult.getLocations().size() - 1; Location location = locationResult.getLocations().get(latestIndex); // 更新标记 updateCurrentLocationMarker(location); // 如果只需要一次位置,可以停止更新 fusedLocationClient.removeLocationUpdates(locationCallback); } } };
3. 触发位置获取逻辑
修改onRequestPermissionsResult和onMapReady方法,在权限授权成功后调用getCurrentLocation():
// 修改onRequestPermissionsResult @Override public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { super.onRequestPermissionsResult(requestCode, permissions, grantResults); if (requestCode == 1001) { boolean fineLocationGranted = grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED; boolean coarseLocationGranted = grantResults.length > 1 && grantResults[1] == PackageManager.PERMISSION_GRANTED; if (fineLocationGranted || coarseLocationGranted) { if (map != null) { try { map.setMyLocationEnabled(true); map.animateCamera(CameraUpdateFactory.zoomTo(15)); // 获取当前位置并更新标记 getCurrentLocation(); } catch (SecurityException e) { e.printStackTrace(); } } } else { Toast.makeText(mContext, "需要位置权限才能显示你的位置", Toast.LENGTH_SHORT).show(); } } } // 修改onMapReady @Override public void onMapReady(GoogleMap googleMap) { map = googleMap; if (ActivityCompat.checkSelfPermission(mContext, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(mContext, Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) { requestPermissions(new String[]{Manifest.permission.ACCESS_FINE_LOCATION, Manifest.permission.ACCESS_COARSE_LOCATION}, 1001); return; } map.setMyLocationEnabled(true); map.animateCamera(CameraUpdateFactory.zoomTo(15)); // 直接获取当前位置 getCurrentLocation(); }
三、额外注意事项
- 确保你的Google Maps API Key已经启用了Maps SDK for Android和Location Services,否则会无法加载地图或获取位置。
- 测试时请打开设备的位置服务(GPS或网络定位)。
- 针对Android 12+的应用,需要额外处理权限申请的弹窗逻辑,确保用户授予位置权限。
这样修改后,你的地图应该能正常显示你的位置标记,setMyLocationEnabled的红色下划线也会消失啦。
内容的提问来源于stack exchange,提问作者BlueYeti81

