改造可选和必填字段

问题描述 投票:0回答:5

使用 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
作为选项?

android retrofit retrofit2
5个回答
73
投票

@FieldMap
@Query
参数都支持可选字段。正如您所提到的,如果您不想传递值,只需传递
null
即可。


25
投票

在题中卡了几个小时,终于解题了

我会用 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有什么区别?

我希望它也对某人有所帮助。


0
投票

Retrofit2(与 Retrofit1 不同)不接受

@FiledMap
中的空值(抛出异常)。 传递给
@Field
/
@Query
参数的空值被忽略(不出现在 http-request 中)


0
投票

是的,瑞安说对了。

在 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);

此语法将采用跳过整数值(如果需要,在服务器端处理)。


0
投票

您可以在 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 中删除所有空查询参数。

© www.soinside.com 2019 - 2024. All rights reserved.