使用FusedLocationProviderClient结合接近传感器获位置遇阻:卡在isSuccessful()判断
排查FusedLocationProviderClient获取位置卡在isSuccessful()的问题
我来帮你定位这个问题!你提到代码卡在task.isSuccessful()的判断里,说明getLastLocation()的任务要么执行失败,要么返回的结果有问题。咱们从几个常见的点入手分析:
1. 先补全日志,明确失败原因
你现在的onComplete里只有成功分支,完全不知道失败时的具体情况。先补上else分支,打印错误信息,这样能精准定位问题:
location.addOnCompleteListener(new OnCompleteListener() { @Override public void onComplete(@NonNull Task task) { if ( task.isSuccessful() ) { // 你的现有逻辑 } else { // 新增:打印失败原因 Log.e("LocationFail", "任务执行失败: " + task.getException()); } } });
这一步能帮你快速区分是权限问题、位置服务未开启,还是其他异常导致的任务失败。
2. 警惕getLastLocation()的局限性
getLastLocation()是个容易踩坑的方法——它只返回设备最近缓存的位置,如果设备很久没定位、位置服务刚开启,或者缓存的位置已经失效,这个方法会返回null,甚至直接导致任务失败。
如果你的需求是获取实时位置,建议替换成getCurrentLocation(),这个方法会主动触发定位(而非依赖缓存),可靠性高很多。示例代码如下:
// 先初始化LocationRequest,设置定位优先级和更新间隔 LocationRequest locationRequest = LocationRequest.create(); locationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY); locationRequest.setInterval(10000); locationRequest.setFastestInterval(5000); // 检查设备位置设置是否满足定位要求 LocationSettingsRequest.Builder settingsBuilder = new LocationSettingsRequest.Builder() .addLocationRequest(locationRequest); SettingsClient settingsClient = LocationServices.getSettingsClient(this); Task<LocationSettingsResponse> settingsTask = settingsClient.checkLocationSettings(settingsBuilder.build()); settingsTask.addOnSuccessListener(settingsResponse -> { // 位置设置符合要求,开始获取当前位置 if (ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) { return; } mFusedLocationProviderClient.getCurrentLocation(LocationRequest.PRIORITY_HIGH_ACCURACY, null) .addOnCompleteListener(locationTask -> { if (locationTask.isSuccessful() && locationTask.getResult() != null) { Location currentLocation = locationTask.getResult(); double lat = currentLocation.getLatitude(); double lon = currentLocation.getLongitude(); Log.d("LocationSuccess", "纬度: " + lat + ", 经度: " + lon); // 执行你的添加标记、地图操作逻辑 addMarker(lat, lon); final LatLng sydney = new LatLng(lat, lon); mapFragment.mapView.getMapAsync(googleMap -> googleMap.addMarker(new MarkerOptions().position(sydney)) ); } else { Log.e("LocationError", "获取实时位置失败: " + locationTask.getException()); } }); }); settingsTask.addOnFailureListener(e -> { if (e instanceof ResolvableApiException) { // 位置设置不满足(比如GPS没开),引导用户开启 try { ResolvableApiException resolvableException = (ResolvableApiException) e; resolvableException.startResolutionForResult(this, 1001); // 1001是自定义请求码 } catch (IntentSender.SendIntentException sendEx) { Log.e("SettingsError", "跳转位置设置失败: " + sendEx); } } });
3. 权限检查的优化
你现在把权限检查放在try-catch里,但这个检查不会抛出异常,完全没必要。同时要确保:
- Manifest文件里已经声明了
ACCESS_FINE_LOCATION和ACCESS_COARSE_LOCATION权限; - Android 6.0+设备上,已经通过动态申请流程拿到了对应权限(不能只靠Manifest声明)。
如果权限没拿到,所有定位相关的任务都会直接失败。
4. 初始化FusedLocationProviderClient的优化
你现在每次调用getDeviceLocation()都重新初始化mFusedLocationProviderClient,这既没必要也会增加资源消耗。建议在Activity的onCreate()里只初始化一次:
@Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.your_layout); // 仅初始化一次 mFusedLocationProviderClient = LocationServices.getFusedLocationProviderClient(this); // 其他初始化逻辑 }
最后,别忘了在onActivityResult里处理位置设置的返回结果,如果用户开启了位置服务,就重新调用获取位置的方法:
@Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { super.onActivityResult(requestCode, resultCode, data); if (requestCode == 1001) { if (resultCode == RESULT_OK) { // 用户开启了位置服务,重新获取位置 getDeviceLocation(); } } }
内容的提问来源于stack exchange,提问作者coder188642
相关产品推荐
相关产品推荐

