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

Android中Kotlin用khttp发POST请求遇NetworkOnMainThreadException问题解决

解决Android中Kotlin POST请求的NetworkOnMainThreadException问题

咱们先把这个问题拆解开来看:

一、NetworkOnMainThreadException是什么?

这是Android系统强制的主线程规则导致的异常:Android不允许在*主线程(UI线程)*中执行网络请求这类耗时操作。因为主线程负责处理UI渲染和用户交互,如果被网络请求阻塞,会导致App卡顿、无响应,甚至触发ANR(Application Not Responding)错误。你的khttp post请求是同步执行的,直接在主线程调用就触发了这个限制。

二、针对khttp的修复方案:把请求移到后台线程

khttp本身是同步网络库,所以你需要把它放到后台线程执行,推荐用Kotlin协程(Android官方推荐的异步处理方式),示例代码如下:

// 假设代码在Activity/Fragment中,使用lifecycleScope绑定生命周期
lifecycleScope.launch(Dispatchers.IO) {
    // 先把EditText的内容转成String,避免直接传递Editable对象
    val payload = mapOf(
        "review" to addReviewET.text.toString(),
        "rating" to quantity.toString(),
        "id_user" to "1",
        "id_movie" to id.toString()
    )
    try {
        // 在IO线程执行网络请求
        val r = post(localhost.insertReview(), data = payload)
        // 请求完成后切回主线程处理结果(比如更新UI)
        withContext(Dispatchers.Main) {
            println(r.text)
            // 这里可以添加成功提示、刷新页面等UI操作
        }
    } catch (e: Exception) {
        // 处理网络异常,比如无网络、请求超时等
        withContext(Dispatchers.Main) {
            e.printStackTrace()
            // 显示错误提示给用户
        }
    }
}

如果你的代码在ViewModel中,可以替换成viewModelScope,效果是一样的,都是自动管理协程生命周期,避免内存泄漏。

三、更适合Android的POST请求替代方案

虽然khttp能用,但Android生态中有更成熟、更适配的网络库,推荐以下两种:

1. Retrofit(官方推荐,最常用)

Retrofit是Square出品的网络库,配合Kotlin协程使用非常流畅,步骤如下:

第一步:添加依赖(在app模块的build.gradle中)

implementation 'com.squareup.retrofit2:retrofit:2.9.0'
implementation 'com.squareup.retrofit2:converter-gson:2.9.0'
implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.6.4'

第二步:定义API接口和数据实体

// API接口,定义POST请求的路径和参数
interface MovieReviewApi {
    @POST("insertReview") // 替换成你的接口相对路径
    suspend fun submitReview(@Body request: ReviewRequest): Response<ReviewResponse>
}

// 请求参数实体类,对应接口需要的字段
data class ReviewRequest(
    val review: String,
    val rating: String,
    val id_user: String,
    val id_movie: String
)

// 响应实体类,根据你的API返回结构调整
data class ReviewResponse(
    val status: String,
    val message: String
)

第三步:创建Retrofit实例并发起请求

// 在合适的地方初始化Retrofit(比如Application类或ViewModel)
val retrofit = Retrofit.Builder()
    .baseUrl("http://你的服务器地址/") // 替换成你的baseUrl
    .addConverterFactory(GsonConverterFactory.create())
    .build()

val reviewApi = retrofit.create(MovieReviewApi::class.java)

// 在协程中发起请求
lifecycleScope.launch(Dispatchers.IO) {
    val request = ReviewRequest(
        review = addReviewET.text.toString(),
        rating = quantity.toString(),
        id_user = "1",
        id_movie = id.toString()
    )
    try {
        val response = reviewApi.submitReview(request)
        withContext(Dispatchers.Main) {
            if (response.isSuccessful) {
                println(response.body()?.message)
                // 处理成功逻辑,比如弹窗提示
            } else {
                println("请求失败:${response.errorBody()?.string()}")
            }
        }
    } catch (e: Exception) {
        withContext(Dispatchers.Main) {
            e.printStackTrace()
            // 处理网络异常
        }
    }
}

2. OkHttp(Retrofit的底层依赖,可直接使用)

如果你不想用Retrofit的封装,也可以直接用OkHttp:

val okHttpClient = OkHttpClient()

lifecycleScope.launch(Dispatchers.IO) {
    // 构造JSON请求体
    val requestBody = JSONObject().apply {
        put("review", addReviewET.text.toString())
        put("rating", quantity.toString())
        put("id_user", "1")
        put("id_movie", id.toString())
    }.toString()

    val request = Request.Builder()
        .url(localhost.insertReview())
        .post(RequestBody.create(MediaType.parse("application/json; charset=utf-8"), requestBody))
        .build()

    try {
        val response = okHttpClient.newCall(request).execute()
        withContext(Dispatchers.Main) {
            println(response.body()?.string())
            // 处理响应
        }
    } catch (e: Exception) {
        withContext(Dispatchers.Main) {
            e.printStackTrace()
        }
    }
}

总结

核心问题就是不能在主线程执行网络请求,不管用哪个库,都要把网络操作放到后台线程。推荐优先用Retrofit+协程,因为它的封装更规范,能减少重复代码,也更符合Android的最佳实践。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.11 09:17:41