Android Studio中如何实现每次启动应用都正常获取当前位置及地址
Android 稳定获取当前位置及完整地址解决方案
你遇到的问题核心有两个:getLastLocation()依赖系统缓存极易返回空、Geocoder 同步方法直接在主线程调用容易超时失败。可按以下方案修改:
1. 核心问题说明
getLastLocation()只会读取系统缓存的位置信息,当缓存过期、设备从未记录过位置、定位开关刚打开时,大概率返回null,无法满足启动必获取的需求Geocoder.getFromLocation()是网络/IO 同步操作,Android 9及以上系统禁止在主线程调用该接口,直接执行会触发ANR、超时、返回空等问题
2. 具体修改方案
2.1 替换缓存位置请求为实时位置请求
使用FusedLocationProviderClient主动请求实时位置,不要依赖缓存,同时提前检查权限和定位开关状态:
private FusedLocationProviderClient fusedLocationClient; private LocationRequest locationRequest; private LocationCallback locationCallback; @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { View root = inflater.inflate(R.layout.your_layout, container, false); userLocation = root.findViewById(R.id.user_location_tv); fusedLocationClient = LocationServices.getFusedLocationProviderClient(requireContext()); // 配置位置请求参数 locationRequest = LocationRequest.create(); locationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY); locationRequest.setInterval(10000); locationRequest.setFastestInterval(5000); locationRequest.setNumUpdates(1); // 仅获取1次位置就停止更新,降低功耗 // 位置结果回调 locationCallback = new LocationCallback() { @Override public void onLocationResult(@NonNull LocationResult locationResult) { super.onLocationResult(locationResult); Location location = locationResult.getLastLocation(); if (location != null) { Log.e("Getting Lat", String.valueOf(location.getLatitude())); Log.e("Getting Long", String.valueOf(location.getLongitude())); // 子线程执行逆地理编码,避免阻塞主线程 new Thread(() -> { String address = getCompleteAddressString(location.getLatitude(), location.getLongitude()); // 切回主线程更新UI requireActivity().runOnUiThread(() -> { userLocation.setText(address.trim()); }); }).start(); // 拿到位置后主动移除回调,避免持续耗电 fusedLocationClient.removeLocationUpdates(locationCallback); } } }; // 先检查定位服务是否开启 LocationManager locationManager = (LocationManager) requireContext().getSystemService(Context.LOCATION_SERVICE); boolean isGpsEnabled = locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER); boolean isNetworkEnabled = locationManager.isProviderEnabled(LocationManager.NETWORK_PROVIDER); if (!isGpsEnabled && !isNetworkEnabled) { Toast.makeText(requireContext(), "请先开启定位服务", Toast.LENGTH_SHORT).show(); // 可选:跳转到系统定位设置页 startActivity(new Intent(Settings.ACTION_LOCATION_SOURCE_SETTINGS)); return root; } // 检查位置权限 if (ContextCompat.checkSelfPermission(requireContext(), Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED) { fusedLocationClient.requestLocationUpdates(locationRequest, locationCallback, Looper.getMainLooper()); } else { // 申请位置权限,权限申请通过回调中重新执行上述位置请求逻辑即可 requestPermissions(new String[]{Manifest.permission.ACCESS_FINE_LOCATION}, 1001); } return root; }
2.2 优化逆地理编码逻辑
getCompleteAddressString 本身逻辑不需要大改,增加默认值和空判断即可,确保在子线程调用:
private String getCompleteAddressString(double LATITUDE, double LONGITUDE) { String strAdd = "暂无地址信息"; // 增加默认返回值,避免空展示 Geocoder geocoder = new Geocoder(requireContext(), Locale.getDefault()); try { List<Address> addresses = geocoder.getFromLocation(LATITUDE, LONGITUDE, 1); if (addresses != null && !addresses.isEmpty()) { Address returnedAddress = addresses.get(0); StringBuilder strReturnedAddress = new StringBuilder(); for (int i = 0; i <= returnedAddress.getMaxAddressLineIndex(); i++) { strReturnedAddress.append(returnedAddress.getAddressLine(i)).append("\n"); } strAdd = strReturnedAddress.toString().trim(); Log.e("My location address", strAdd); } else { Log.e("My Current location address", "No Address returned!"); } } catch (IOException e) { e.printStackTrace(); Log.e("My Current location address", "Cannot get Address!"); } return strAdd; }
3. 补充优化建议
- 国内无Google服务的设备可替换为系统原生
LocationManager请求位置,稳定性更高 - 若
Geocoder频繁返回空,可接入高德、百度等国内地图服务商的逆地理编码接口,适配性更好 - 可增加3次以内的重试机制,每次间隔1s,进一步提升成功率
内容的提问来源于stack exchange,提问作者Sainita
相关产品推荐
相关产品推荐

