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

如何在Kotlin中使用Retrofit 2动态生成带多查询参数的API链接

在Kotlin中用Retrofit 2动态生成带多查询参数的API链接

方法1:使用@QueryMap简化动态参数传递

这种方式适合统一管理参数,比逐个声明@Query更灵活,尤其适合参数数量不固定的场景。

修改接口类

将多个独立的@Query参数替换为@QueryMap,通过Map统一传递所有参数:

interface CalorieCalculationInterface {
    @GET("/macrocalculator")
    fun getData(@QueryMap params: Map<String, @JvmSuppressWildcards Any?>): Call<CalorieCalculationDataResponse>
}
  • @JvmSuppressWildcards用于兼容Java泛型,支持Int、Double等不同类型的参数值
  • Map的key对应查询参数名(如"age"、"gender"),value为参数值;null值会被自动忽略,不会拼入URL

修改调用代码

将所有参数封装进Map,还可根据条件动态添加/移除参数:

private fun getData(ageNum: Int, gender: String, heightNum: Double, weightNum: Double, activityLevel: Int, goalLevel: String) {
    // 构建参数Map
    val params = mutableMapOf(
        "age" to ageNum,
        "gender" to gender,
        "height" to heightNum,
        "weight" to weightNum,
        "activitylevel" to activityLevel,
        "goal" to goalLevel
    )
    // 示例:根据条件动态添加可选参数
    // if (needOptionalParam) params["optional_key"] = optionalValue

    GlobalScope.launch(Dispatchers.IO) {
        try {
            val retrofit = Retrofit.Builder()
                .baseUrl("https://fitness-calculator.p.rapidapi.com/")
                .addConverterFactory(GsonConverterFactory.create())
                .client(OkHttpClient.Builder().addInterceptor { chain ->
                    val newRequest = chain.request().newBuilder()
                        .addHeader(
                            "X-RapidAPI-Key",
                            "75ef70a478msh3da1c20824c8e15p13575ejsn26185c236f61"
                        ).build()
                    chain.proceed(newRequest)
                }.build())
                .build()

            val retrofitData = retrofit.create(CalorieCalculationInterface::class.java)
            val response = retrofitData.getData(params).awaitResponse()
            
            withContext(Dispatchers.Main) {
                if (response.isSuccessful) {
                    val responseBody = response.body()
                    val calculate = responseBody?.data?.calorie
                    calcuView.text = calculate?.toString() ?: "数据获取失败"
                }
            }
        } catch (e: Exception) {
            e.printStackTrace() // 不要吞异常,方便排查问题
            withContext(Dispatchers.Main) {
                calcuView.text = "请求出错"
            }
        }
    }
}

方法2:使用@Url + HttpUrl.Builder完全自定义URL

如果需要更灵活控制URL结构(比如动态修改路径、baseUrl),可以手动构建HttpUrl:

修改接口类

去掉@GET的固定路径,改用@Url参数接收自定义URL:

interface CalorieCalculationInterface {
    @GET
    fun getData(@Url url: HttpUrl): Call<CalorieCalculationDataResponse>
}

修改调用代码

通过HttpUrl.Builder动态拼接所有查询参数:

private fun getData(ageNum: Int, gender: String, heightNum: Double, weightNum: Double, activityLevel: Int, goalLevel: String) {
    GlobalScope.launch(Dispatchers.IO) {
        try {
            // 手动构建完整URL
            val httpUrl = HttpUrl.parse("https://fitness-calculator.p.rapidapi.com/macrocalculator")?.newBuilder()
                ?.addQueryParameter("age", ageNum.toString())
                ?.addQueryParameter("gender", gender)
                ?.addQueryParameter("height", heightNum.toString())
                ?.addQueryParameter("weight", weightNum.toString())
                ?.addQueryParameter("activitylevel", activityLevel.toString())
                ?.addQueryParameter("goal", goalLevel)
                // 示例:动态添加可选参数
                // ?.addQueryParameter("optional_key", optionalValue)
                ?.build() ?: throw IllegalArgumentException("无效URL")

            val retrofit = Retrofit.Builder()
                .baseUrl("https://fitness-calculator.p.rapidapi.com/")
                .addConverterFactory(GsonConverterFactory.create())
                .client(OkHttpClient.Builder().addInterceptor { chain ->
                    val newRequest = chain.request().newBuilder()
                        .addHeader(
                            "X-RapidAPI-Key",
                            "75ef70a478msh3da1c20824c8e15p13575ejsn26185c236f61"
                        ).build()
                    chain.proceed(newRequest)
                }.build())
                .build()

            val retrofitData = retrofit.create(CalorieCalculationInterface::class.java)
            val response = retrofitData.getData(httpUrl).awaitResponse()
            
            withContext(Dispatchers.Main) {
                if (response.isSuccessful) {
                    val responseBody = response.body()
                    val calculate = responseBody?.data?.calorie
                    calcuView.text = calculate?.toString() ?: "数据获取失败"
                }
            }
        } catch (e: Exception) {
            e.printStackTrace()
            withContext(Dispatchers.Main) {
                calcuView.text = "请求出错"
            }
        }
    }
}

额外提示

  1. 避免使用GlobalScope:推荐使用自定义CoroutineScope(如viewModelScope或lifecycleScope),防止内存泄漏
  2. 不要吞异常:catch块中打印异常信息,便于排查请求失败原因
  3. 处理null值:使用@QueryMap时null值会自动忽略;使用HttpUrl.Builder需判断非null再添加参数

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.20 14:23:16