Android中Geocoder.getFromLocationName调用超时挂起问题求助
Geocoder.getFromLocationName()抛出DEADLINE_EXCEEDED异常排查与解决
问题重现
尝试通过Kotlin调用Geocoder.getFromLocationName()将文本地址转换为坐标,代码实现如下:
import android.location.Geocoder val geocoder = Geocoder(context, Locale.getDefault()) try { val result = geocoder.getFromLocationName(club.location, 1) // 执行到此挂起后抛出异常 Log.d(LOG_TAG, "${club.location} translates into cordinates : ${result[0].latitude}, ${result[0].longitude}") } catch (ex : Exception){ Log.d(LOG_TAG, "${ex.message}") }
触发的异常栈信息:
Caused by: java.io.IOException: DEADLINE_EXCEEDED: ClientCall started after deadline exceeded: -15.077367176s from now at android.location.Geocoder$SynchronousGeocoder.getResults(Geocoder.java:388) at android.location.Geocoder.getFromLocationName(Geocoder.java:277) at android.location.Geocoder.getFromLocationName(Geocoder.java:202)
解决方案
必须在子线程执行同步Geocoder调用
Geocoder.getFromLocationName()是同步方法,底层依赖网络请求解析地址,在主线程执行极易因超时触发DEADLINE_EXCEEDED异常。建议用协程将调用切换到IO线程:lifecycleScope.launch(Dispatchers.IO) { val geocoder = Geocoder(context, Locale.getDefault()) try { val result = geocoder.getFromLocationName(club.location, 1) if (result.isNotEmpty()) { val lat = result[0].latitude val lng = result[0].longitude // 需更新UI时切回主线程 withContext(Dispatchers.Main) { Log.d(LOG_TAG, "${club.location} 转换坐标:$lat, $lng") } } else { Log.d(LOG_TAG, "未匹配到有效地址") } } catch (ex: Exception) { Log.d(LOG_TAG, "地理编码失败:${ex.message}") } }检查Google Play服务状态
原生Geocoder依赖设备上的Google Play服务,若服务缺失或禁用会导致请求失败。可通过以下代码检查:val status = GoogleApiAvailability.getInstance().isGooglePlayServicesAvailable(context) if (status != ConnectionResult.SUCCESS) { Log.d(LOG_TAG, "Google Play服务不可用,错误码:$status") // 提示用户修复Google服务 }确认网络权限配置
在AndroidManifest.xml中添加必要的网络权限:<uses-permission android:name="android.permission.INTERNET" /> <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />优化地址输入格式
模糊、不规范的地址会增加服务解析时间,尽量提供完整地址(如「中国北京市朝阳区XX街道XX号」),避免使用缩写或模糊描述。改用Google Maps Geocoding API(备选方案)
若原生Geocoder问题无法解决,可直接调用Google Maps Geocoding API,手动控制超时参数:val client = OkHttpClient.Builder() .connectTimeout(30, TimeUnit.SECONDS) .readTimeout(30, TimeUnit.SECONDS) .build() val encodedAddress = URLEncoder.encode(club.location, "UTF-8") val url = "https://maps.googleapis.com/maps/api/geocode/json?address=$encodedAddress&key=你的API密钥" val request = Request.Builder().url(url).build() lifecycleScope.launch(Dispatchers.IO) { try { val response = client.newCall(request).execute() val responseBody = response.body?.string() ?: return@launch // 用Gson/Moshi等库解析JSON获取坐标 val jsonObject = JSONObject(responseBody) val results = jsonObject.getJSONArray("results") if (results.length() > 0) { val location = results.getJSONObject(0) .getJSONObject("geometry") .getJSONObject("location") val lat = location.getDouble("lat") val lng = location.getDouble("lng") withContext(Dispatchers.Main) { Log.d(LOG_TAG, "${club.location} 转换坐标:$lat, $lng") } } } catch (ex: Exception) { Log.d(LOG_TAG, "API请求失败:${ex.message}") } }
内容的提问来源于stack exchange,提问作者choufei
相关产品推荐
相关产品推荐

