Android使用Geocoder调用getFromLocation遇DEADLINE_EXCEEDED崩溃问题
崩溃原因分析
这个崩溃是因为Geocoder的逆地理编码请求超时,触发了java.io.IOException: DEADLINE_EXCEEDED异常:
- Geocoder底层依赖系统地理服务(如Google位置服务),当服务在规定时间内无法返回地址结果时,会抛出该超时异常。
- 部分Android系统版本中,这种IO异常不会被
GeocodeListener的onError回调捕获,而是直接向上抛出,导致应用崩溃。
解决办法
- 捕获IO异常:在调用
getFromLocation的代码块外添加try-catch,直接捕获超时或其他IO异常:
try { geocoder.getFromLocation( latLng.latitude, latLng.longitude, 1, object : Geocoder.GeocodeListener { override fun onGeocode(addresses: MutableList<Address>) { addresses.firstOrNull()?.getAddressLine(0)?.let { onAddressResult(it, null) } ?: run { onAddressResult(null, "无可用地址信息") } } override fun onError(errorMessage: String?) { onAddressResult(null, errorMessage ?: "未知错误") } } ) } catch (e: IOException) { onAddressResult(null, "地址解析超时:${e.message}") }
- 提前检查Geocoder可用性:调用
getFromLocation前,先通过Geocoder.isPresent()判断设备是否支持地理编码服务,避免无效请求:
if (!Geocoder.isPresent()) { onAddressResult(null, "设备不支持地址解析服务") return }
- 优化地址解析逻辑:避免直接调用
addresses.first(),改用firstOrNull()做空安全处理,防止空列表导致的额外崩溃:
override fun onGeocode(addresses: MutableList<Address>) { val addressLine = addresses.firstOrNull()?.getAddressLine(0) if (addressLine != null) { onAddressResult(addressLine, null) } else { onAddressResult(null, "未解析到有效地址") } }
- 添加重试机制(可选):针对超时异常,可实现有限次数的重试逻辑(比如最多重试2次),但需设置合理的重试间隔(如1秒),避免频繁请求加重服务负担:
private var retryCount = 0 private fun fetchAddress(latLng: LatLng) { if (retryCount >= 2) { onAddressResult(null, "多次请求超时,请稍后再试") retryCount = 0 return } try { geocoder.getFromLocation( latLng.latitude, latLng.longitude, 1, object : Geocoder.GeocodeListener { override fun onGeocode(addresses: MutableList<Address>) { addresses.firstOrNull()?.getAddressLine(0)?.let { onAddressResult(it, null) } ?: run { onAddressResult(null, "无可用地址信息") } retryCount = 0 } override fun onError(errorMessage: String?) { if ("DEADLINE_EXCEEDED" in (errorMessage ?: "")) { retryCount++ Handler(Looper.getMainLooper()).postDelayed({ fetchAddress(latLng) }, 1000) } else { onAddressResult(null, errorMessage) retryCount = 0 } } } ) } catch (e: IOException) { if ("DEADLINE_EXCEEDED" in e.message ?: "") { retryCount++ Handler(Looper.getMainLooper()).postDelayed({ fetchAddress(latLng) }, 1000) } else { onAddressResult(null, e.message) retryCount = 0 } } }
内容的提问来源于stack exchange,提问作者Chandra Shekhar
相关产品推荐
相关产品推荐

