
请求参数从传递方式可分三种:url参数,请求主体以及表单编码。我们来一一讨论。
url参数就是在url链接后面的键值对,例如 https://api.weibo.com/2//statuses/public_timeline.json?access_token=xxx 中,access_token就是url参数,xxx为其值。
Retrofit定义url参数非常直接,只要在方法参数前面添加@Query("key")注解即可。@Query中key的值与url中的参数名称是一致的,Retrofit会自动添加这些参数到url中。
以之前获取微博公共动态的API为例,具体API详见 http://open.weibo.com/wiki/2/statuses/public_timeline 。从接口中看到,必选参数只有access_token一个,我们定义个方法如下:
方法timelineForPublic需要参数token,Retrofit会通过@Query中定义的名称access_token将token映射成请求参数access_token。此时,请求url就会变成:
从获取微博公共动态的API中我们可以看到,除了必选的access_token,还有三个可选参数count、page以及base_app,也就是说现在请求参数有四个了。有了上面定义请求参数的介绍,我们只需要往方法上添加相应的参数并用@Query进行注解:
此时,如果我们只需要传递access_token,而不需要其他参数,则可以在调用方法的时候传null。当然,我们不能传null给int这样的原生类型,而需要使用对应的Integer。而Retrofit会跳过值为null的参数,并在组装请求的时候忽略它们。
获取公共微博最多有四个参数,那么我们再查看下获取好友微博API http://open.weibo.com/wiki/2/statuses/friends_timeline ,发现其有一个必选参数以及七个可选参数,也就是方法会有八个参数。那么问题来了,如果有更多的可选参数,那方法的参数是不是也会特别多,而且很多时候我们只需要其中一两个请求参数,却需要提供所有的参数值,显然很繁琐。为了处理这种情况,QueryMap就该登场了。
我们可以使用下面的方式定义获取公共微博API的方法:
@QueryMap后面需要紧跟着一个Map<String, String >类型,这样就可以动态地添加查询参数了。如果说只需要accept_token参数,则可以像下面这样调用:
这样,我们只需要传递我们需要设置的参数就可以了。
在我们查看微博的各个API时,会发现每个请求都需要一个access_token参数,于是我们就在所有的方法中都添加了对应的参数。那么有没有简单的方式来给每个请求都添加相同的参数,从而不需要每个请求都做相同处理呢?
强大的Retrofit是支持的,但是是通过OkHttp中的拦截器来实现的。我们在 《Retrofit之初体验》 提及过,Retrofit直接依赖OkHttp,使用OkHttp作为底层网络客户端。而使用OkHttp可以添加拦截器,用来修改即将发出去的请求,这个可以参见 《OkHttp之拦截器》 。这样我们就可以在拦截器中,对每个请求添加一个access_token参数了:
首先获取到了HttpUrl对象,然后基于原始的HttpUrl对象创建一个新的构建器,从而可以使用addQueryPatameter()方法添加额外的查询参数,最后将这个新的HttpUrl对象通过Request.Builder方法设置到Request中。
在我们实际应用中,大多数时候会通过请求主体向服务器发送数据。以我们的惯例,都会以微博API为例,但可惜的是并没有找过微博使用这种方式的API,而都使用的是表单方式,这个会在后面讨论。所以个很常见的例子,那就是登陆,通常请求参数如下:
好的,登录的方法定义如下:
其中LoginParam.java类如下:
首先,我们使用了@Body注解了方法参数,而我们在创建Retrofit.Builder的时候也为其添加了GsonConverter转换器。
这样,Retrofit会将LoginParam对象转换为Json,并将其作为主体数据添加到请求中,支持了使用请求主体向服务器发送数据。
在上面我们使用了用请求主体的方式来向服务器发送数据,除了这种方式,还可以通过表单编码(form-urlencoded)的形式。微博API中的写入接口都是采用这种方式向服务器发送数据的,我们这里以转发微博为例,具体API详见 http://open.weibo.com/wiki/2/statuses/repost 。
首先,定义转发微博的方法:
我们看到了@FormUrlEncoded注解,这个注解不能使用在GET请求上,因为它代表要想服务器发送数据。此外,在参数id上使用@Field注解,表示请求会发送此参数到服务器,而@Field("id")中的id则定义的是参数名称。
与@Query类似,当你有多个参数要发送时,只需要使用@Field注解它们即可。同样与@QueryMap对应的有个@FieldMap注解,具体使用类似。
@Field与@FieldMap都有一个属性encoded,表示键值对是否进行url编码,默认为false。以@Field为例,使用如下:
了解完@Field之后,我们讨论下表单编码与url参数的区别:表单编码使用在POST请求中的,而url参数是用在GET请求中的。表单编码使用请求主体发送数据到服务器,而不是url参数。而url参数的使用主要是为了从服务器过滤或者获取指定的数据。
Ok,本文就讨论到这里,感谢大家的阅读,下文我们将讨论Retrofit如何定义请求头。
如果你对retrofit感兴趣,同时你也觉得我的文章可以给你带来那么一丢丢的帮助,敬请关注,后续会继续介绍Retrofit的相关使用。
源码地址:
https://github.com/FILWAndroid/DevJourney
关于源码:
get 方法的参数 Type 和 Annotation[] 分别 对应 定义的api方法的 返回值Type 和 方法的注解 ,下图比较清晰。
图中可以看出 returnType 对应 LiveData<LoginInfo> ,而 annotations 则对应 POST和FormUrlEncoded 。
但是 returnType 直接获取到的不是 LiveData ,上一篇文章就说到 Type的几个子接口类 ,这里就要用到了。
先调用辅助方法 getRawType(returnType) ,取得原始类型,判断是否是 LiveData.class ,不是的话返回 null ,这样 retrofit就会循环下一个Factory ,直到 返回值不为空的CallAdapter 。
如果原始类型是 LiveData.class ,则判断是否是 ParameterizedType ,否则抛出异常。通过 getParameterUpperBound(0, (ParameterizedType) returnType) 获取泛型 Type responseType ,最后将这个 responseType 作为参数传给 CallAdapter 。
PS:这里使用 getRawType(responseType) 的话,得到的原始类型会是 LoginInfo 。
从上面可知, get方法可以理解为判断是否是对应的CallAdapter和取得必要参数的方法 。而且还可以通过在 定义的api方法(如:login)那里添加注解 来做一些特殊 *** 作。
这里继续以上面的 LiveData<LoginInfo> 为例,可以在 adapt 方法创建一个 LiveData 且作为返回值返回。
然后通过 call 访问接口获取数据,将返回来的数据通过 livaData.postValue() 通知到外部,这样就完成了获取数据且关联了生命周期。
上图所示,创建 LoginService 调用 login 方法,因为返回的是 LiveData 所以使用起来跟普通的一样就好了,设置 Observer ,在 onChanged 方法回调更新数据。
1、Retrofit创建2、Retrofit实现Cookie自动化管理
3、Retrofit,Gson解析,请求返回的类型不统一,假如double返回的是null
4、请求参数日志打印
5、统一请求参数添加到请求头中
6、统一请求参数添加到请求body中
7、缓存的拦截器
8、BaseUrl动态切换
9、拦截指定接口,动态更改返回值便于测试
点击传送查看
点击传送查看
1.第一种办法,依赖第三方库
配置信息如下
2.第二种办法,拦截器拦截(个人推荐第二种,可控性高)
给大家推荐一个打印日志库,很漂亮的日志结构
然后在httpClientBuilder中添加拦截
然后在httpClientBuilder中添加拦截
然后在httpClientBuilder中添加拦截
然后在httpClientBuilder中添加拦截
用了一个博客中民间大神的拦截动态替换baseUrl方法有点问题,我暂时用了一种简单粗暴方法
上边的路径是我随便写的,post中写全路径,这个优先级最高,同时设置了baseUrl不受影响
给大家一个专门写动态替换baseUrl连接 传送门
有时候我们需要返回指定值测试,可能需要空或者null等,迫于无法修改服务器返回数据,也没必要让后台修改数据,所以引发一个问题,如果拦截返回内容并修改指定字段值
然后在httpClientBuilder中添加拦截
欢迎分享,转载请注明来源:内存溢出
微信扫一扫
支付宝扫一扫
评论列表(0条)