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

从iOS转Android开发:Retrofit POST请求参数传递、序列化方法及代码错误排查

问题分析与解决方案

嘿,刚从iOS转Android确实得适应下Retrofit的逻辑差异,我帮你拆解下代码里的问题,顺便讲清楚POST请求参数传递和序列化的正确姿势~

核心错误:请求格式不匹配

你在Postman里用的是JSON格式的请求体,但代码里用了@Field注解——这个注解是用来发送application/x-www-form-urlencoded类型的表单数据的,和接口要求的JSON格式完全不兼容,这就是接口调用失败的根本原因!

修正方案(分两种写法)

写法1:不用数据类(临时方案)

直接用JsonObject来构建请求体,配合@Body注解传递:

// 修正后的接口定义
interface ApiRequests {
    @POST("/startup")
    fun getDataVenom(@Body requestBody: JsonObject): Call<ObjectFromResponse>
}

// 请求方法里构建请求体
private fun getCurrentData() {
    tv_textView.visibility = View.GONE
    tv_timeStamp.visibility = View.GONE
    progressBar.visibility = View.VISIBLE
    
    val api2 = Retrofit.Builder()
        .baseUrl(BASE_URL_VENOM)
        .addConverterFactory(GsonConverterFactory.create())
        .build()
        .create(ApiRequests::class.java)
    
    // 构建符合要求的JSON请求体
    val requestBody = JsonObject().apply {
        val playersArray = JsonArray()
        playersArray.add("player")
        add("players", playersArray)
        addProperty("action", "add")
    }

    GlobalScope.launch(Dispatchers.IO) {
        try {
            val response = api2.getDataVenom(requestBody).awaitResponse()
            if (response.isSuccessful) {
                val data = response.body()!!
                Log.d(TAG, data.toString())
                withContext(Dispatchers.Main) {
                    tv_textView.visibility = View.VISIBLE
                    tv_timeStamp.visibility = View.VISIBLE
                    progressBar.visibility = View.GONE
                }
            } else {
                // 打印错误信息方便调试
                Log.e(TAG, "请求失败: ${response.errorBody()?.string()}")
            }
        } catch (e: Exception) {
            withContext(Dispatchers.Main){
                Toast.makeText(
                    applicationContext,
                    "Seems like something went wrong...",
                    Toast.LENGTH_SHORT
                ).show()
            }
        }
    }
}

写法2:用数据类(推荐方案,更简洁易维护)

Retrofit配合Gson转换器可以自动把数据类序列化成JSON,这是Android开发的标准写法:

  1. 先定义请求体的数据类:
// 完全匹配接口要求的JSON结构
data class StartupRequest(
    val players: List<String>,
    val action: String
)
  1. 修正接口定义:
interface ApiRequests {
    @POST("/startup")
    fun getDataVenom(@Body request: StartupRequest): Call<ObjectFromResponse>
}
  1. 请求时直接创建数据类对象:
private fun getCurrentData() {
    tv_textView.visibility = View.GONE
    tv_timeStamp.visibility = View.GONE
    progressBar.visibility = View.VISIBLE
    
    val api2 = Retrofit.Builder()
        .baseUrl(BASE_URL_VENOM)
        .addConverterFactory(GsonConverterFactory.create())
        .build()
        .create(ApiRequests::class.java)
    
    // 直接创建符合结构的请求对象
    val request = StartupRequest(listOf("player"), "add")

    GlobalScope.launch(Dispatchers.IO) {
        try {
            val response = api2.getDataVenom(request).awaitResponse()
            if (response.isSuccessful) {
                val data = response.body()!!
                Log.d(TAG, data.toString())
                withContext(Dispatchers.Main) {
                    tv_textView.visibility = View.VISIBLE
                    tv_timeStamp.visibility = View.VISIBLE
                    progressBar.visibility = View.GONE
                }
            } else {
                Log.e(TAG, "请求失败: ${response.errorBody()?.string()}")
            }
        } catch (e: Exception) {
            withContext(Dispatchers.Main){
                Toast.makeText(
                    applicationContext,
                    "Seems like something went wrong...",
                    Toast.LENGTH_SHORT
                ).show()
            }
        }
    }
}

额外优化建议

  1. 不要每次请求都创建Retrofit实例:Retrofit初始化比较耗时,建议把它做成单例(比如用object类或者依赖注入框架),复用同一个实例。
  2. 避免使用GlobalScope:GlobalScope的生命周期不受页面控制,容易引发内存泄漏,推荐用LifecycleScope(和页面生命周期绑定)或者ViewModel里的viewModelScope。
  3. 完善错误处理:除了捕获异常,还要处理response.isSuccessful为false的情况,打印response.errorBody()能帮你快速定位接口返回的错误信息。

关于Retrofit POST请求参数传递与序列化的总结

  • JSON请求体(最常用):用@Body注解,配合数据类(推荐)、JsonObject或Map,Gson转换器会自动完成对象到JSON的序列化。
  • 表单数据:如果接口要求application/x-www-form-urlencoded格式,需要给接口方法加上@FormUrlEncoded注解,然后用@Field传递单个参数。
  • 路径参数:比如/user/{id},用@Path("id")注解传递。
  • 查询参数:比如/user?name=xxx,用@Query("name")注解传递。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.29 12:52:34