使用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
相关产品推荐
相关产品推荐

