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

使用Google Geocoder API获取地址时遇NetworkOnMainThreadException,协程调用仍崩溃

Geocoder调用出现NetworkOnMainThreadException随机崩溃的解决办法

问题现象

调用Google Geocoder的getFromLocation方法根据经纬度获取地址时,随机触发NetworkOnMainThreadException崩溃,崩溃日志如下:

Fatal Exception: android.os.NetworkOnMainThreadException:
       at android.os.Parcel.createException(Parcel.java:1952)
       at android.os.Parcel.readException(Parcel.java:1910)
       at android.os.Parcel.readException(Parcel.java:1860)
       at android.location.ILocationManager$Stub$Proxy.getFromLocation(ILocationManager.java:949)
       at android.location.Geocoder.getFromLocation(Geocoder.java:133)
       at com.ui.activities.map.MapViewModel$getAddress$1.invokeSuspend(MapViewModel.kt:21)
       at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:33)
       at kotlinx.coroutines.internal.DispatchedContinuationKt.resumeCancellableWith(DispatchedContinuation.kt:367)
       at kotlinx.coroutines.intrinsics.CancellableKt.startCoroutineCancellable(Cancellable.kt:30)
       at kotlinx.coroutines.intrinsics.CancellableKt.startCoroutineCancellable$default(Cancellable.kt:25)
       at kotlinx.coroutines.CoroutineStart.invoke(CoroutineStart.kt:110)
       at kotlinx.coroutines.AbstractCoroutine.start(AbstractCoroutine.kt:126)
       at kotlinx.coroutines.BuildersKt__Builders_commonKt.launch(Builders.common.kt:56)
       at kotlinx.coroutines.BuildersKt.launch(BuildersKt.java:1)
       at kotlinx.coroutines.BuildersKt__Builders_commonKt.launch$default(Builders.common.kt:47)
       at kotlinx.coroutines.BuildersKt.launch$default(BuildersKt.java:1)
       at com.ui.activities.map.MapViewModel.getAddress(MapViewModel.kt:19)
       at com.ui.activities.MapActivity.reload(MapActivity.java:1275)
       at com.ui.activities.MapActivity.onMapReady(MapActivity.java:1259)
       at com.google.android.gms.maps.zzat.zzb(com.google.android.gms:play-services-maps@@18.0.0:1)
       at com.google.android.gms.maps.internal.zzaq.zza(com.google.android.gms:play-services-maps@@18.0.0:5)
       at com.google.android.gms.internal.maps.zzb.onTransact(com.google.android.gms:play-services-maps@@18.0.0:3)
       at android.os.Binder.transact(Binder.java:667)
       at fd.c(fd.java:2)
       at com.google.maps.api.android.lib6.impl.bg.run(bg.java:1)
       at android.os.Handler.handleCallback(Handler.java:873)
       at android.os.Handler.dispatchMessage(Handler.java:99)
       at android.os.Looper.loop(Looper.java:193)
       at android.app.ActivityThread.main(ActivityThread.java:6669)
       at java.lang.reflect.Method.invoke(Method.java)
       at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:493)
       at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:858)

已尝试用协程包裹调用逻辑,但崩溃仍未解决,代码如下:

fun getAddress(latitude: Double, longitude: Double) {
    val geocoder = Geocoder(app, Locale.getDefault())
    viewModelScope.launch {
        try {
            val addresses = geocoder.getFromLocation(latitude, longitude, 1)  
            addressObserver.value = addresses
        }catch (ex: Exception){
            ex.printStackTrace()
        }

    }
}

问题原因

viewModelScope.launch()默认使用Dispatchers.Main调度器,即协程代码在主线程执行。而Geocoder.getFromLocation()在本地无地址缓存时会发起网络请求,主线程执行网络操作直接触发NetworkOnMainThreadException。

解决方法

在协程中切换到Dispatchers.IO调度器执行getFromLocation耗时操作,完成后切回主线程更新LiveData:

修改后的代码:

fun getAddress(latitude: Double, longitude: Double) {
    val geocoder = Geocoder(app, Locale.getDefault())
    viewModelScope.launch {
        try {
            // 切换到IO线程执行地址查询
            val addresses = withContext(Dispatchers.IO) {
                geocoder.getFromLocation(latitude, longitude, 1)
            }
            // 主线程更新LiveData
            addressObserver.value = addresses
        } catch (ex: Exception) {
            ex.printStackTrace()
            // 可添加自定义异常处理,比如给LiveData设置错误状态
        }
    }
}

额外优化建议

  • getFromLocation可能返回null或抛出IO异常、服务不可用等错误,建议补充针对性的异常处理逻辑。
  • 可添加超时控制,避免协程长时间挂起:
    val addresses = withContext(Dispatchers.IO) {
        withTimeoutOrNull(5000) {
            geocoder.getFromLocation(latitude, longitude, 1)
        }
    }
    

内容的提问来源于stack exchange,提问作者Adnan

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.10 13:50:28