使用 Retrofit 时,我知道你可以使用
@FieldMap Map<String, String> options
来指定可选查询。
假设我有一个 api 调用,它有 2 个必填字段和 3 个可选字段。
我将如何格式化这些电话?
会不会像
Call<Response> getStuff(@Query("user_id") String userId, @Query("password") String password, @FieldMap Map<String, String> options)
或者整个事情会是一个单一的@FieldMap,比如:
Call<Response> getStuff(@FieldMap Map<String, String> options)
使用此选项,您是否只需填写必填字段,然后使用
null
作为选项?
@FieldMap
和 @Query
参数都支持可选字段。正如您所提到的,如果您不想传递值,只需传递null
即可。
在题中卡了几个小时,终于解题了
我会用 Kotlin 来回答这个问题。
正如@Ryan 所说,您也可以将
null
作为 Kotlin 中的值传递:
fun getStuff(@Query("user_id") userId: String? = null ,
@Query("password") password: String? = null,
@FieldMap options: Map<String, String>? = null): Call<Response>
如果你在 Java 中有像
@Query("page") int page
这样的可选字段,你应该记住一些事情:
在 Java 中,您不能为原始数据类型传递 null,例如
int
、float
、long
等
相反,使用
Integer
、Float
、Long
等,编译器不会脾气暴躁。
所以正确答案是:
@Query("page") Integer page
.
在 Kotlin 中,您不能为
Int
、Float
、Long
等原始数据类型传递 null
使用
Int?
而不是 Int
和 Retrofit 将在组装请求时忽略它们。
这是因为当 Kotlin 在 JVM 上编译时,这种类型的不可空值表示为原始类型
int
的值,像Int?
这样的可空值是一个装箱类型。
那么在 Kotlin 中,一个可为 null 的 Int Int?可以解决这个问题。
有关Kotlin原语的更多信息,请参阅:Kotlin中Int和Integer有什么区别?
我希望它也对某人有所帮助。
Retrofit2(与 Retrofit1 不同)不接受
@FiledMap
中的空值(抛出异常)。
传递给 @Field
/@Query
参数的空值被忽略(不出现在 http-request 中)
是的,瑞安说对了。
在 Java 中,您的调用示例将是:
Call<Response> getStuff(null,null,@FieldMap Map<String, String> options);
记住这将与“字符串”完美配合
如果您想将“int”或“float”保留为可选,请不要使用原始数据类型,如 int、float、long 等。相反,请使用 Integer、Float、Long 等
所以你的带有可选整数和浮点数的例子将是:
Call<Response> getStuff(@Query("user_id") Integer userId, @Query("password") Float password, @FieldMap Map<String, String> options);
此语法将采用跳过整数值(如果需要,在服务器端处理)。
您可以在 okhttp 客户端中使用自定义拦截器来实现此目的。
val NULL_STRING = "null"
class QueryParamInterceptor : Interceptor {
override fun intercept(chain: Interceptor.Chain): Response {
val request = chain.request()
val urlBuilder = request.url.newBuilder()
for (queryName in request.url.queryParameterNames) {
val queryValue = request.url.queryParameter(queryName)
if (queryValue?.toLowerCase() == NULL_STRING) {
urlBuilder.removeAllQueryParameters(queryName)
continue
}
}
Log.d("TAG", "intercept: ${urlBuilder.build()}")
val newRequest = request.newBuilder()
.url(urlBuilder.build())
.build()
return chain.proceed(newRequest)
}
}
上面的代码解析每个 URL 并在发现 null 时从 URL 中删除。您可以使用以下代码在 OkHttp 客户端中进行设置。
val httpClient: OkHttpClient.Builder =
OkHttpClient.Builder().addInterceptor(interceptor)
.addInterceptor(QueryParamInterceptor())
下次调用 API 时,它会自动从 URL 中删除所有空查询参数。