Android Lollipop版本地图定位搜索失败,Marshmallow及以上正常求解决方案
嘿,我来帮你捋捋Android Lollipop上定位失败的问题——这个情况我之前也碰到过,主要是Lollipop和Marshmallow+在定位机制、权限处理上的差异导致的,下面给你具体的排查点和修复方案:
问题根源拆解
你的代码在Marshmallow及以上正常,但Lollipop失效,大概率是这几个原因:
- Lollipop采用安装时授权模型,如果Manifest里没正确声明定位权限,会直接导致定位服务无法调用
getBestProvider可能返回null(比如设备禁用了所有定位服务),你直接使用会引发异常或获取不到位置getLastKnownLocation在Lollipop中经常返回null,因为设备可能没有缓存的位置数据,而你没有等待requestLocationUpdates的回调就直接同步获取- 部分Lollipop设备的Geocoder因谷歌服务版本低或网络问题,无法返回地址信息
具体修复方案
1. 补全Manifest中的权限声明
Lollipop不需要运行时请求权限,但必须在AndroidManifest.xml中声明必要的定位权限:
<!-- 高精度定位权限 --> <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" /> <!-- 低精度(网络)定位权限 --> <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" /> <!-- 地址解析需要网络,添加网络权限 --> <uses-permission android:name="android.permission.INTERNET" />
2. 处理定位提供者为空的边界情况
不要直接使用getBestProvider返回的结果,先判断是否为空,同时添加备用的定位提供者:
Criteria criteria = new Criteria(); criteria.setAccuracy(Criteria.ACCURACY_FINE); // 指定高精度定位 criteria.setPowerRequirement(Criteria.POWER_MEDIUM); // 平衡功耗和精度 String provider = locationManager.getBestProvider(criteria, true); // 无合适提供者时,手动降级到可用的定位方式 if (provider == null) { if (locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER)) { provider = LocationManager.GPS_PROVIDER; } else if (locationManager.isProviderEnabled(LocationManager.NETWORK_PROVIDER)) { provider = LocationManager.NETWORK_PROVIDER; } else { // 提示用户开启定位服务 Toast.makeText(this, "请先开启设备定位服务", Toast.LENGTH_SHORT).show(); return; } }
3. 改用LocationListener回调获取位置(核心修复)
getLastKnownLocation在Lollipop中非常不可靠,因为很多时候没有缓存的位置数据。你应该依赖requestLocationUpdates的回调来获取实时位置:
// 定义位置监听器,处理位置更新 private LocationListener locationListener = new LocationListener() { @Override public void onLocationChanged(Location location) { if (location != null) { // 获取到位置后,更新地图和地址信息 updateMapWithLocation(location); // 拿到位置后停止更新,避免不必要的耗电 locationManager.removeUpdates(this); } } // 实现其他必需的接口方法 @Override public void onStatusChanged(String provider, int status, Bundle extras) {} @Override public void onProviderEnabled(String provider) {} @Override public void onProviderDisabled(String provider) {} }; // 封装地图更新逻辑 private void updateMapWithLocation(Location location) { LatLng current = new LatLng(location.getLatitude(), location.getLongitude()); Geocoder gcd = new Geocoder(this, Locale.getDefault()); List<Address> addresses = null; String addr = ""; // 先检查Geocoder是否可用 if (!Geocoder.isPresent()) { Toast.makeText(this, "地址解析服务不可用", Toast.LENGTH_SHORT).show(); } else { try { addresses = gcd.getFromLocation(current.latitude, current.longitude, 1); Log.e(TAG, "addresses: "+addresses ); } catch (IOException e) { e.printStackTrace(); Toast.makeText(this, "获取地址失败,请检查网络", Toast.LENGTH_SHORT).show(); } if (addresses != null && addresses.size() > 0) { addr = addresses.get(0).getAddressLine(0); } } // 更新地图标记 if (CurrMarker != null) { CurrMarker.remove(); // 移除旧标记 } CurrMarker = googleMap.addMarker(new MarkerOptions() .position(current) .title("Current Position") .snippet(addr)); addCameraToMap(current); }
然后修改初始化逻辑,优先请求实时位置,同时用getLastKnownLocation作为备用:
// 注册位置监听 locationManager.requestLocationUpdates(provider, 1000, 1, locationListener); // 尝试获取最后已知位置(作为快速显示的备用) Location lastKnownLocation = locationManager.getLastKnownLocation(provider); if (lastKnownLocation != null) { updateMapWithLocation(lastKnownLocation); } else { Toast.makeText(this, "正在获取实时位置...", Toast.LENGTH_SHORT).show(); }
4. 优化Geocoder的异常处理
在Lollipop中,Geocoder经常因为网络或服务问题返回null,所以提前检查服务可用性,同时添加网络状态判断会更稳妥。
总结
按照上面的步骤修改后,应该能解决Lollipop上的定位问题。核心思路是:确保权限声明正确、处理定位提供者的边界情况、依赖监听回调获取可靠的实时位置、完善Geocoder的异常处理。
内容的提问来源于stack exchange,提问作者mohamed fazurullah
相关产品推荐
相关产品推荐

