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

如何修复Kotlin项目中Google Play控制台的NetworkOnMainThreadException问题

修复android.os.NetworkOnMainThreadException错误

问题背景

我的Kotlin项目在Google Play控制台的稳定性模块检测到android.os.NetworkOnMainThreadException错误,相关代码及错误信息如下:

关键错误代码片段

private fun getLocation(latitude: Double, longitude: Double){
    try {
        geoCoder = Geocoder(this@SignUpActivity, Locale.ENGLISH)
        // 此处触发网络操作,主线程执行导致异常
        val addresses = geoCoder.getFromLocation(latitude, longitude, 1)

        val countryName = addresses?.get(0)?.countryName
        val countryCode = addresses?.get(0)?.countryCode
        val state = addresses?.get(0)?.adminArea
        val city = addresses?.get(0)?.locality

        val locationData = LocationModelClass(
            userLatitude = latitude,
            userLongitude = longitude,
            userCountryName = countryName,
            userCountryCode = countryCode,
            userState = state,
            userCity = city
        )
        locationViewModel.setUserSignUpLocationData(locationModelClass = locationData)
    } catch (e: IOException) {
        e.printStackTrace()
    }
}

错误截图

NetworkOnMainThreadException错误截图

错误原因

Geocoder.getFromLocation()方法内部可能发起网络请求获取地理编码数据,当前代码直接在**主线程(UI线程)**中调用该方法,违反Android主线程规则——主线程禁止执行耗时网络操作,因此抛出NetworkOnMainThreadException。

修复方案

推荐使用Kotlin协程将地理编码操作移至后台线程执行,完成后切换回主线程更新ViewModel数据,以下提供两种实现方式:

方案1:在Activity中直接用协程修改getLocation方法

private fun getLocation(latitude: Double, longitude: Double){
    lifecycleScope.launch(Dispatchers.IO) {
        try {
            geoCoder = Geocoder(this@SignUpActivity, Locale.ENGLISH)
            val addresses = geoCoder.getFromLocation(latitude, longitude, 1)

            val countryName = addresses?.get(0)?.countryName
            val countryCode = addresses?.get(0)?.countryCode
            val state = addresses?.get(0)?.adminArea
            val city = addresses?.get(0)?.locality

            val locationData = LocationModelClass(
                userLatitude = latitude,
                userLongitude = longitude,
                userCountryName = countryName,
                userCountryCode = countryCode,
                userState = state,
                userCity = city
            )
            // 切换回主线程更新ViewModel
            withContext(Dispatchers.Main) {
                locationViewModel.setUserSignUpLocationData(locationModelClass = locationData)
            }
        } catch (e: IOException) {
            e.printStackTrace()
            // 主线程提示解析失败
            withContext(Dispatchers.Main) {
                Toast.makeText(this@SignUpActivity, "地理编码解析失败", Toast.LENGTH_SHORT).show()
            }
        }
    }
}

方案2:将地理编码逻辑移至ViewModel(符合MVVM架构)

  1. 修改LocationViewModel,添加协程处理逻辑:
class LocationViewModel : ViewModel() {
    private val userLocationData: MutableLiveData<LocationModelClass> = MutableLiveData()

    fun setUserSignUpLocationData(locationModelClass: LocationModelClass) {
        userLocationData.value = locationModelClass
    }

    fun getUserSignUpLocationData(): MutableLiveData<LocationModelClass> {
        return userLocationData
    }

    // 新增:后台处理地理编码
    fun fetchGeocodeData(context: Context, latitude: Double, longitude: Double) {
        viewModelScope.launch(Dispatchers.IO) {
            try {
                val geoCoder = Geocoder(context, Locale.ENGLISH)
                val addresses = geoCoder.getFromLocation(latitude, longitude, 1)

                val countryName = addresses?.get(0)?.countryName
                val countryCode = addresses?.get(0)?.countryCode
                val state = addresses?.get(0)?.adminArea
                val city = addresses?.get(0)?.locality

                val locationData = LocationModelClass(
                    userLatitude = latitude,
                    userLongitude = longitude,
                    userCountryName = countryName,
                    userCountryCode = countryCode,
                    userState = state,
                    userCity = city
                )
                // 主线程更新LiveData
                withContext(Dispatchers.Main) {
                    userLocationData.value = locationData
                }
            } catch (e: IOException) {
                e.printStackTrace()
            }
        }
    }
}
  1. 在Activity的startLocationUpdate中调用ViewModel方法:
private fun startLocationUpdate() {
    locationViewModelLatLong.getLocationData().observe(this, Observer {
        val la = it.latitude
        val lo = it.longitude
        Log.d("SignUpActivity", "getLocationData() it.userLatitude$la")
        Log.d("SignUpActivity", "getLocationData() it.userLatitude$lo")
        // 调用ViewModel方法处理地理编码
        locationViewModel.fetchGeocodeData(this@SignUpActivity, la, lo)
    })
}

额外注意事项

  • 确保项目已添加协程依赖,在Module级别的build.gradle中添加:
dependencies {
    implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:1.7.3"
    implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:2.6.2"
    implementation "androidx.lifecycle:lifecycle-runtime-ktx:2.6.2"
}
  • Geocoder在部分设备上可能解析失败,建议完善错误处理逻辑,避免影响后续流程。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.03 18:05:49