点击定位FAB无权限弹窗:MapFragment定位功能异常求助
问题分析与解决方案
我看了你的代码和日志,马上就发现问题所在了——你的代码只处理了位置权限的校验,完全没检查系统的位置服务是否开启!
从场景2的日志能看到,点击FAB后走到了Inside try,但没进入权限检查的分支,说明用户已经授予了位置权限,但此时系统的位置服务是关闭的。这时候getLastKnownLocation()会返回null,而你的代码里既没有对currentLocation == null的情况做处理,也没有触发异常(所以catch块也不会执行),自然就没任何反应了。
修复步骤
1. 添加位置服务状态检查方法
先写一个工具方法,用来判断系统的位置服务是否开启:
private boolean isLocationServiceEnabled() { LocationManager locationManager = (LocationManager) getContext().getSystemService(Context.LOCATION_SERVICE); // 检查GPS或网络定位是否至少有一个开启 return locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER) || locationManager.isProviderEnabled(LocationManager.NETWORK_PROVIDER); }
2. 修改FAB点击事件逻辑
在获取当前位置之前,先检查位置服务是否开启,如果没开启,就引导用户跳转到位置设置页面:
locationButton.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { Log.v("MapFragment", "Location button pressed" ); try { Log.v("MapFragment", "Inside try" ); // 第一步:检查权限 if (ActivityCompat.checkSelfPermission(getActivity(), android.Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(getContext(), android.Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) { Log.v("MapFragment", "Requesting location permissions"); ActivityCompat.requestPermissions(getActivity(), new String[]{Manifest.permission.ACCESS_FINE_LOCATION, Manifest.permission.ACCESS_COARSE_LOCATION}, MY_PERMISSIONS_REQUEST_LOCATION); return; } // 第二步:检查位置服务是否开启 if (!isLocationServiceEnabled()) { // 弹出对话框引导用户开启位置服务 new AlertDialog.Builder(getContext()) .setTitle("位置服务未开启") .setMessage("需要开启位置服务才能获取当前位置") .setPositiveButton("去设置", new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { // 跳转到位置设置页面 Intent intent = new Intent(Settings.ACTION_LOCATION_SOURCE_SETTINGS); startActivity(intent); } }) .setNegativeButton("取消", null) .show(); return; } // 第三步:获取位置并更新地图 currentLocation = getLastKnownLocation(); if (currentLocation != null) { Log.v("MapFragment", "Updating map to current location"); CameraUpdate cameraUpdate = CameraUpdateFactory.newLatLngZoom( new LatLng(currentLocation.getLatitude(), currentLocation.getLongitude()), 17); googleMap.animateCamera(cameraUpdate); locationButton.getDrawable().setColorFilter( ContextCompat.getColor(getContext(), R.color.colorPrimary), PorterDuff.Mode.SRC_IN); } else { // 位置服务开启但暂时获取不到位置的情况 Toast.makeText(getContext(), "正在获取位置,请稍候", Toast.LENGTH_SHORT).show(); // 可以在这里注册位置监听,实时获取位置 } } catch (Exception e){ Log.e("MapFragment", "Error getting location", e); Toast.makeText(getContext(), "获取位置失败,请检查设置", Toast.LENGTH_SHORT).show(); } } });
3. 优化getLastKnownLocation()方法
原来的方法里在循环中重复请求权限,这会导致多次弹出权限对话框,直接把权限检查移到方法外面(我们已经在点击事件里做过权限检查了),简化方法:
private Location getLastKnownLocation() { LocationManager mLocationManager = (LocationManager) getContext().getSystemService(LOCATION_SERVICE); List<String> providers = mLocationManager.getProviders(true); Location bestLocation = null; for (String provider : providers) { // 权限已经在外部检查过了,这里不用再判断 Location l = mLocationManager.getLastKnownLocation(provider); if (l == null) { continue; } if (bestLocation == null || l.getAccuracy() < bestLocation.getAccuracy()) { bestLocation = l; } } return bestLocation; }
额外建议
- 处理权限请求的回调:重写
onRequestPermissionsResult方法,当用户授予权限后,可以自动尝试获取位置 - 如果
getLastKnownLocation()返回null(比如刚开启位置服务还没获取到位置),可以注册LocationListener来监听位置变化,实时更新地图
这样修改后,当用户关闭位置服务时点击FAB,就会弹出对话框引导用户去设置开启,开启后回到应用再点击FAB就能正常获取位置了。
内容的提问来源于stack exchange,提问作者OzoneX
相关产品推荐
相关产品推荐

