如何在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 = "请求出错" } } } }
额外提示
- 避免使用
GlobalScope:推荐使用自定义CoroutineScope(如viewModelScope或lifecycleScope),防止内存泄漏 - 不要吞异常:catch块中打印异常信息,便于排查请求失败原因
- 处理null值:使用
@QueryMap时null值会自动忽略;使用HttpUrl.Builder需判断非null再添加参数
内容的提问来源于stack exchange,提问作者user15593139
相关产品推荐
相关产品推荐

