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

Kotlin使用OkHttp发起网络请求报NetworkOnMainThreadException如何解决

报错原因

Android系统强制禁止在主线程(UI线程)执行耗时的网络请求操作,你代码中调用的client.newCall(request).execute()是同步阻塞方法,直接在主线程运行会触发android.os.NetworkOnMainThreadException异常。
该限制的设计初衷是避免网络请求阻塞主线程导致页面卡顿、无响应(ANR),保障用户交互体验。

解决方案

方案1:使用OkHttp自带异步请求(无额外依赖)

将同步execute()替换为异步enqueue()方法,请求自动在OkHttp管理的子线程执行,结果回调后切回主线程更新UI即可,修改后代码如下:

@SuppressLint("SetTextI18n")
fun wordCall() {
    val textView: TextView = findViewById(R.id.blue)
    val client = OkHttpClient()
    // 直接传入字符串url即可,无需额外转为URL类
    val url = "https://reqres.in/api/users?page=2"
    val request = Request.Builder()
        .url(url)
        .get()
        .build()

    client.newCall(request).enqueue(object : Callback {
        override fun onFailure(call: Call, e: IOException) {
            // 子线程回调,更新UI需切主线程
            runOnUiThread {
                textView.text = "请求失败:${e.message}"
            }
        }

        override fun onResponse(call: Call, response: Response) {
            val responseBody = response.body?.string() ?: "响应内容为空"
            // 子线程回调,更新UI需切主线程
            runOnUiThread {
                textView.text = "Response Body: $responseBody"
            }
        }
    })
}

注意事项:

  • 回调默认运行在子线程,直接操作UI会报错,必须通过runOnUiThread、Handler等方式切换到主线程再更新TextView。
  • 避免用!!处理响应体,用空安全调用+默认值可规避空指针崩溃。

方案2:使用Kotlin协程(代码更简洁,推荐)

如果项目已引入Kotlin协程,用协程处理异步逻辑可读性更高,且可以和页面生命周期绑定避免内存泄漏。
首先确认模块级build.gradle已添加协程依赖(已引入可跳过):

dependencies {
    implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:1.7.3"
}

修改后的请求代码:

@SuppressLint("SetTextI18n")
fun wordCall() {
    val textView: TextView = findViewById(R.id.blue)
    val client = OkHttpClient()
    val url = "https://reqres.in/api/users?page=2"
    val request = Request.Builder()
        .url(url)
        .get()
        .build()

    // 绑定Activity生命周期的协程作用域,页面销毁自动取消请求
    lifecycleScope.launch {
        val result = withContext(Dispatchers.IO) {
            // 网络请求放在IO线程执行,不阻塞主线程
            try {
                val response = client.newCall(request).execute()
                response.body?.string() ?: "响应内容为空"
            } catch (e: Exception) {
                "请求失败:${e.message}"
            }
        }
        // 自动回到主线程,可直接更新UI
        textView.text = "Response Body: $result"
    }
}

注意事项:

  • lifecycleScope需要引入AndroidX Lifecycle KTX依赖,常规AndroidX项目默认已包含。
  • 耗时的网络请求必须放在Dispatchers.IO调度的线程执行。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.04 17:18:01