Android首次安装应用使用fusedLocationProviderClient获取位置出错如何解决
代码核心问题排查
- 错误调用
fusedLocationProviderClient.flushLocations():这个API的作用是清空所有本地缓存的位置数据,新设备首次安装时本身就没有历史位置缓存,调用这个方法会直接导致getLastLocation()返回null,完全失去了缓存读取的作用,反而增加了定位开销。 - 刚请求位置更新就立即移除回调:你在调用
requestLocationUpdates()之后,紧接着就执行了removeLocationUpdates(locationCallback),相当于刚向系统注册定位请求就直接注销,系统根本没有时间触发位置回调返回定位结果,这是首次安装定位失败的核心原因。 - 位置回调逻辑不完整:
LocationCallback里只给经纬度变量赋值,没有后续的地址解析、UI更新逻辑,就算拿到位置也不会刷新页面内容,用户只能反复点击按钮重试。 - 缺少边界情况处理:没有判断Geocoder返回的地址列表是否为空,也没有处理定位权限未授权、设备定位开关未打开的异常场景。
优化实现方案
首先要删掉无用的flushLocations()调用,保留位置回调直到拿到定位结果再注销,补充完整回调里的业务逻辑,增加异常场景处理。修正后的代码如下:
// 把LocationCallback提为成员变量,避免被GC回收,也方便后续注销 private LocationCallback locationCallback; private final int LOCATION_PERMISSION_REQ_CODE = 1001; private void getCurrentLocation() { // 先检查定位权限是否已授权 if (ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED && ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) { // 未授权则申请权限 ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.ACCESS_FINE_LOCATION}, LOCATION_PERMISSION_REQ_CODE); return; } // 检查设备定位开关是否打开,可选但建议添加 LocationManager locationManager = (LocationManager) getSystemService(Context.LOCATION_SERVICE); if (!locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER) && !locationManager.isProviderEnabled(LocationManager.NETWORK_PROVIDER)) { Toast.makeText(this, "请先打开设备定位开关", Toast.LENGTH_SHORT).show(); // 可以跳转到系统定位设置页,此处省略逻辑 return; } // 删掉flushLocations调用,不需要清缓存 fusedLocationProviderClient.getLastLocation().addOnCompleteListener(new OnCompleteListener<Location>() { @Override public void onComplete(@NonNull Task<Location> task) { Location location = task.getResult(); if (location != null) { parseLocationToAddress(location); } else { // 没有缓存位置,请求单次定位 LocationRequest locationRequest = LocationRequest.create() .setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY) .setInterval(10000) .setFastestInterval(1000) .setNumUpdates(1); locationCallback = new LocationCallback() { @Override public void onLocationResult(@NonNull LocationResult locationResult) { super.onLocationResult(locationResult); Location location1 = locationResult.getLastLocation(); if (location1 != null) { parseLocationToAddress(location1); // 拿到定位结果后再注销回调 fusedLocationProviderClient.removeLocationUpdates(locationCallback); } } }; fusedLocationProviderClient.requestLocationUpdates(locationRequest, locationCallback, Looper.getMainLooper()); Toast.makeText(getApplicationContext(), "正在获取位置,请稍候", Toast.LENGTH_LONG).show(); } } }); } // 把地址解析逻辑抽成公共方法,避免重复代码 private void parseLocationToAddress(Location location) { BuyerLatitude = String.valueOf(location.getLatitude()); BuyerLongitude = String.valueOf(location.getLongitude()); Geocoder geocoder = new Geocoder(BuyerAreaFinderActivity.this, Locale.getDefault()); try { List<Address> addresses = geocoder.getFromLocation(location.getLatitude(), location.getLongitude(), 1); if (addresses != null && !addresses.isEmpty()) { String address = addresses.get(0).getAddressLine(0); BuyerArea.setText(address); BuyerAreaFetchBtn.setVisibility(View.INVISIBLE); } else { Toast.makeText(this, "无法解析当前位置地址", Toast.LENGTH_SHORT).show(); } } catch (IOException e) { e.printStackTrace(); Toast.makeText(this, "地址解析失败,请检查网络", Toast.LENGTH_SHORT).show(); } } // 页面销毁时注销回调,避免内存泄漏 @Override protected void onDestroy() { super.onDestroy(); if (locationCallback != null) { fusedLocationProviderClient.removeLocationUpdates(locationCallback); } } // 处理权限申请结果 @Override public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { super.onRequestPermissionsResult(requestCode, permissions, grantResults); if (requestCode == LOCATION_PERMISSION_REQ_CODE) { if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) { getCurrentLocation(); } else { Toast.makeText(this, "需要定位权限才能获取位置信息", Toast.LENGTH_SHORT).show(); } } }
额外优化建议
- 如果对定位精度要求不是极高,可以把
PRIORITY_HIGH_ACCURACY换成PRIORITY_BALANCED_POWER_ACCURACY,定位速度更快,功耗更低。 - 可以给定位请求加超时逻辑,超过15秒没拿到结果就提示用户检查网络和定位设置,避免无限等待。
内容的提问来源于stack exchange,提问作者user16881253
相关产品推荐
相关产品推荐

