You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.12 08:25:21