您的位置:首页 > 理论基础 > 计算机网络

Android网络请求库 - Say hello to retrofit

2016-10-13 10:37 381 查看
转: Android网络请求库 - Say hello to retrofit

回顾:

Android网络请求库 - Say hello to OkHttp
Android网络请求库 - Say hello to Volley

之前对Android里常用的网络请求库OkHttp与Volley做了简单的学习归纳与总结,这里看这个系列中的最后一篇,来认识一下Retrofit。

Retrofit可以认为是OkHttp的“升级版”。之所以这么说,是因为其内部默认正是基于OkHttp来进行封装的。这点从Retrofit这个命名就可以看出端倪。

回顾一下OkHttp,我们会发现虽然是封装过后的库,但OkHttp的封装是比较“碎片化”的。所以如果不自己再进行封装,使用时代码就比较容易耦合。

而Retrofit作为其升级版,有一个最吸引人的特色就是:将所有的请求封装为interface,并通过“注解”来声明api的相关信息。让你爽到停不下来。


RESTful API

在正式开始了解Retrofit的使用之前,我们有必要先了解一个概念,即RESTful。这是因为Retrofit的初衷就是根据RESTful风格的API来进行封装的。

关于RESTful的学习,可以参考一下RESTful API 设计指南此文。相信看完之后,就会对Restful有一个基本的认识和理解了。

但我们这里可以对RESTful的核心思想做一个最简练的总结,那就是:所谓”资源”,就是网络上的一个实体,或者说是网络上的一个具体信息。那么我们访问API的本质就是与网络上的某个资源进行互动而已。那么,因为我们实质是访问资源,所以RESTful设计思想的提出者Fielding认为:

URI当中不应当出现动词,因为”资源“表示一种实体,所以应该用名词表示,而动词则应该放在HTTP协议当中。那么举个最简单的例子:

xxx.com/api/createUser
xxx.com/api/getUser
xxx.com/api/updateUser
xxx.com/api/deleteUser

这样的API风格我们应该很熟悉,但如果要遵循RESTful的设计思想,那么它们就应该变为类似下面这样:

[POST]xxx.com/api/User
[GET] xxx.com/api/User
[PUT]xxx.com/api/User
[DELETE]xxx.com/api/User

也就是说:因为这四个API都是访问服务器的USER表,所以在RESTful里URL是相同的,而是通过HTTP不同的RequestMethod来区分增删改查的行为。

而有的时候,如果某个API的行为不好用请求方法描述呢?比如说,A向B转账500元。那么,可能会出现如下设计:

POST /accounts/1/transfer/500/to/2

在RESTful的理念里,如果某些动作是HTTP动词表示不了的,你就应该把动作做成一种资源。可以像下面这样使用它:

  POST /transaction HTTP/1.1

  Host: 127.0.0.1

  

  from=1&to=2&amount=500.00

好了,当然实际来说RESTful肯定不是就这点内容。这里我们只是了解一下RESTful最基本和核心的设计理念。


从官方介绍初识Retrofit

当我们要去学习一样新的技术,还有什么是比官方的资料更好的了呢?所以,第一步我们打开网址http://square.github.io/retrofit/。然后开始阅读:

我们发现官方的介绍非常简单粗暴,一上来就通过一个Introduction来展示了如何使用Retrofit来进行一个最基本的请求。下面我们就逐步的分析一下:



从上图中,我们首先注意到了一个关键的说明信息:Retrofit会将你的HTTP API转换为Java中的interface的形式。OK,接着看:



这里我们读到的描述是:Retrofit类可以针对之前定义的interface生成一个具体实现。我们发现官方对此解释的很言简意赅,但更通俗的来讲的话:

也就是说虽然我们之前将此次请求的API信息封装为了一个接口,但我们也知道Java中接口是不能产生对象的,这时Retrofit类就站出来扮演了这个角色。

我们可以将Retrofit类看作是一个“工厂类”的角色,我们在接口中提供了此次的“产品”的生产规格信息,而Retrofit则通过信息负责为我们生产。



这里我们看到了一个重要的东西“Call”:通过之前封装的请求接口对象创建的任一的Call都可以发起一个同步(或异步)的HTTP请求到远程服务器。

之后说了一些通过注解来描述request的好处,然后这个简单的Introduction就结束了。那么,现在我们来简单总结一下,目前为止我们的感受如何。

我觉得就仅从以上简单的介绍当中我们起码有两点直观感受:那就是解耦明确;使用简单。通过注解的方式描述request让人眼前一亮。但与此同时:

我们发现读完Introduction后,仅仅是这个基本的用例中,都仍然有很多小细节需要我们通过实际使用之后才能搞明白。这可能在一定程度上说明了:

为什么说Retrofit的使用门槛相对于其它库来说要更高一些。不过没关系,我们自己先来写一个比官方Introduction更简单的用例,再逐步深入。


动手写第一个Demo来碰坑

现在我们已经阅读完了官方的用例介绍,乍看之下没什么,但实际用起来说不定就得碰坑。为方便测试,仍然通过servlet在本地简单的实现服务器。

我们现在的设想可能是这样的,我只是想要写一个demo来测试一下用Retrofit来成功发起一次最基本的get请求,所以最初的doGet无比简单:
<code class="hljs avrasm has-numbering" style="display: block; padding: 0px; background: transparent; color: inherit; box-sizing: border-box; font-family: "Source Code Pro", monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal;">    public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
response<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.setHeader</span>(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"Content-type"</span>, <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"text/html;charset=UTF-8"</span>)<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">;</span>
PrintWriter <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">out</span> = response<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.getWriter</span>()<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">;</span>
<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">out</span><span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.print</span>(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"{\"describe\":\"请求成功\"}"</span>)<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">;</span>
<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">out</span><span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.flush</span>()<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">;</span>
<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">out</span><span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.close</span>()<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">;</span>
}</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right: 1px solid rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li></ul><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right: 1px solid rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li></ul>


完成了以上代码的编写,然后我们把该servlet的URL配置一下,言简意赅的,就配置为“/api/retrofitTesting”好了。这时服务器就准备完毕了。

很显然,下面我们就可以把焦点放在Android客户端的实现上来了。为了使用Retrofit,所以我们的第一步工作自然就是在自己的项目中设置依赖:



配置好了依赖,接着我们就可以开始编码工作了。还记得官方用例的第一步吗?所以我们要做的显然是模仿它也把我们自己的HTTP API封装成interface。
<code class="hljs cs has-numbering" style="display: block; padding: 0px; background: transparent; color: inherit; box-sizing: border-box; font-family: "Source Code Pro", monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal;"><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">public</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">interface</span> DemoService {
@GET(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"api/retrofitTesting"</span>)
Call<ResponseInfo> testHttpGet();
}
<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// GSON - BEAN</span>
class ResponseInfo {
String describe;
}</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right: 1px solid rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li></ul><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right: 1px solid rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li></ul>


现在我们再来看这个所谓的API接口,可能就更加明确一点了。首先是通过注解@GET来声明本次请求方式为GET以及注明API-URL。

而就之后声明的方法来说:从其为Call的返回类型不难猜想多半与请求的发起有关,因为如果我们对OkHttp有所了解的话,一定就记得下面这样的代码:
<code class="hljs vbscript has-numbering" style="display: block; padding: 0px; background: transparent; color: inherit; box-sizing: border-box; font-family: "Source Code Pro", monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal;">        OkHttpClient client = <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">new</span> OkHttpClient();
<span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">Request</span> <span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">request</span> = <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">new</span> <span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">Request</span>.Builder().url(url).build();
<span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">Response</span> <span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">response</span> = client.newCall(<span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">request</span>).<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">execute</span>();</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right: 1px solid rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li></ul><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right: 1px solid rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li></ul>


newCall方法实际就是返回一个Call类型的实例。而Retrofit中的Call接口相对于OkHttp添加了一个泛型,该泛型用于说明本次请求响应的数据解析类型。

那么这里的泛型为什么是我们自己建立的一个实体类呢?其实回忆一下之前服务器在response中返回的内容(JSON),就不难猜想到与GSON有关。

好的,我们继续按照官方用例中接下来的步骤去完善我们的demo。封装好了interface,接下来自然就是调用了,最终的代码如下:
<code class="hljs java has-numbering" style="display: block; padding: 0px; background: transparent; color: inherit; box-sizing: border-box; font-family: "Source Code Pro", monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal;">    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">private</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">void</span> <span class="hljs-title" style="box-sizing: border-box;">testRetrofitHttpGet</span>() {
<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// step1</span>
Retrofit retrofit = <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">new</span> Retrofit.Builder()
.baseUrl(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"http://192.168.2.100:8080/TestServer/"</span>)
.build();
<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// step2</span>
DemoService service = retrofit.create(DemoService.class);
<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// step3</span>
Call<ResponseInfo> call = service.testHttpGet();
<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// step4</span>
call.enqueue(<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">new</span> Callback<ResponseInfo>() {
<span class="hljs-annotation" style="color: rgb(155, 133, 157); box-sizing: border-box;">@Override</span>
<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">public</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">void</span> <span class="hljs-title" style="box-sizing: border-box;">onResponse</span>(Call<ResponseInfo> call, Response<ResponseInfo> response) {
Log.d(TAG,response.body().describe);
}

<span class="hljs-annotation" style="color: rgb(155, 133, 157); box-sizing: border-box;">@Override</span>
<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">public</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">void</span> <span class="hljs-title" style="box-sizing: border-box;">onFailure</span>(Call<ResponseInfo> call, Throwable t) {
Log.d(TAG, t.getMessage());
}
});
}</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right: 1px solid rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li><li style="box-sizing: border-box; padding: 0px 5px;">12</li><li style="box-sizing: border-box; padding: 0px 5px;">13</li><li style="box-sizing: border-box; padding: 0px 5px;">14</li><li style="box-sizing: border-box; padding: 0px 5px;">15</li><li style="box-sizing: border-box; padding: 0px 5px;">16</li><li style="box-sizing: border-box; padding: 0px 5px;">17</li><li style="box-sizing: border-box; padding: 0px 5px;">18</li><li style="box-sizing: border-box; padding: 0px 5px;">19</li><li style="box-sizing: border-box; padding: 0px 5px;">20</li><li style="box-sizing: border-box; padding: 0px 5px;">21</li><li style="box-sizing: border-box; padding: 0px 5px;">22</li></ul><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right: 1px solid rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li><li style="box-sizing: border-box; padding: 0px 5px;">12</li><li style="box-sizing: border-box; padding: 0px 5px;">13</li><li style="box-sizing: border-box; padding: 0px 5px;">14</li><li style="box-sizing: border-box; padding: 0px 5px;">15</li><li style="box-sizing: border-box; padding: 0px 5px;">16</li><li style="box-sizing: border-box; padding: 0px 5px;">17</li><li style="box-sizing: border-box; padding: 0px 5px;">18</li><li style="box-sizing: border-box; padding: 0px 5px;">19</li><li style="box-sizing: border-box; padding: 0px 5px;">20</li><li style="box-sizing: border-box; padding: 0px 5px;">21</li><li style="box-sizing: border-box; padding: 0px 5px;">22</li></ul>


有了之前的说明并对照官方示例,现在会发现以上代码很容易理解。而我们发现官方没有给出的step4其实也很熟悉,因为它和OkHttp的使用是相同的。

这个时候看上去我们的准备工作就已经完成了,于是兴致勃勃的编译并运行demo来查看一下效果,却发现收到了如下的一个异常:



为什么会出现这种情况呢?蛋疼啊!别急,通过异常信息的描述,我们得知这似乎与类型的转换相关,然后带着这个疑问再去查看官方文档,于是发现:



从上述信息我们得知Retrofit默认只能将响应体转换为OkHttp中的ResponseBody,而我们之前为Call设置的泛型类型是自定义的类型ResponseInfo 。

将JSON格式的数据转换为Java-BEAN,很自然就会想到GSON。而Retrofit如果要执行这种转换是要依赖于另一个库的,所以我们还得在项目中配置另一个依赖:



之后,在构造Retrofit对象的时候加上一句代码就可以了:
<code class="hljs avrasm has-numbering" style="display: block; padding: 0px; background: transparent; color: inherit; box-sizing: border-box; font-family: "Source Code Pro", monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal;">        Retrofit retrofit = new Retrofit<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.Builder</span>()
<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.baseUrl</span>(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"http://192.168.2.100:8080/TestServer/"</span>)
<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.addConverterFactory</span>(GsonConverterFactory<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.create</span>()) // 加上这一句哦,亲
<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.build</span>()<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">;</span></code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right: 1px solid rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li></ul><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right: 1px solid rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li></ul>


这个时候,当我们再次运行程序就没问题了,成功的得到如下的日志打印:



现在,经过我们的一番摸索和折腾,关于Retrofit很基本的第一个demo就捣鼓出来了。

其实这是有意义的,因为回想一下会发现:现在我们对于Retrofit大致的使用套路,在心里已经有个一二三了。


回到官方文档继续学习

前面我们说到对于Retrofit的使用已经有了一个基本的认识和了解,接下来要做的自然就是深入和继续学习更多的使用细节。那么很显然,回到官方吧。



事实上前面我们已经使用到了注解@GET,这里就是告诉我们这种注解其实对于HTTP其它常用的请求方式(GET,POST,PUT,DELETE等等)都封装了。

而对于@GET来说,我们知道HTTP-GET是可以将一些简单的参数信息直接通过URL进行上传的,所以URL又可以像下面那样使用:
<code class="hljs ruby has-numbering" style="display: block; padding: 0px; background: transparent; color: inherit; box-sizing: border-box; font-family: "Source Code Pro", monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal;"><span class="hljs-variable" style="color: rgb(102, 0, 102); box-sizing: border-box;">@GET</span>(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"api/retrofitTesting?param=value"</span>)</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right: 1px solid rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li></ul><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right: 1px solid rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li></ul>



replacement blocks与@path

不知道大家注意到官方示例和我们刚才自己测试写的demo中有一个细小的差别没,就是下面这样的东西:
<code class="hljs java has-numbering" style="display: block; padding: 0px; background: transparent; color: inherit; box-sizing: border-box; font-family: "Source Code Pro", monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal;"><span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">//官方的</span>
<span class="hljs-annotation" style="color: rgb(155, 133, 157); box-sizing: border-box;">@GET</span>(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"users/{user}/repos"</span>)
<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">//我们的</span>
<span class="hljs-annotation" style="color: rgb(155, 133, 157); box-sizing: border-box;">@GET</span>(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"api/retrofitTesting"</span>)</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right: 1px solid rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li></ul><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right: 1px solid rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li></ul>


我们注意到官方的API的URL中有一个”{user}“这样的东西?它的作用是什么呢?我们也能在官方文档上找到答案:



从上述介绍中,我们注意到一个叫做replacement blocks的东西。可以最简单的将其理解为路径替换块,用”{}”表示,与注解@path配合使用。

当然我们自己实际去使用一下能够对其有一个更加深刻的理解,所以我们将我们之前的demo修改一下,变成下面这样:
<code class="hljs java has-numbering" style="display: block; padding: 0px; background: transparent; color: inherit; box-sizing: border-box; font-family: "Source Code Pro", monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal;"><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">public</span> <span class="hljs-class" style="box-sizing: border-box;"><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">interface</span> <span class="hljs-title" style="box-sizing: border-box; color: rgb(102, 0, 102);">DemoService</span> {</span>
<span class="hljs-annotation" style="color: rgb(155, 133, 157); box-sizing: border-box;">@GET</span>(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"api/{name}"</span>)
Call<ResponseInfo> testHttpGet(<span class="hljs-annotation" style="color: rgb(155, 133, 157); box-sizing: border-box;">@Path</span>(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"name"</span>) String apiAction);
}</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right: 1px solid rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li></ul><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right: 1px solid rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li></ul>


使用的方式也会有所不同,我们在调用的使用需要将对应的值传给responseInfo方法。
<code class="hljs sql has-numbering" style="display: block; padding: 0px; background: transparent; color: inherit; box-sizing: border-box; font-family: "Source Code Pro", monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal;"><span class="hljs-operator" style="box-sizing: border-box;"><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">Call</span><ResponseInfo> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">call</span> = service.testHttpGet(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"retrofitTesting"</span>);</span></code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right: 1px solid rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li></ul><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right: 1px solid rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li></ul>


这样修改过后的实际效果实际上与我们之前的demo是一样的,那么这样做的好处是什么?显然是为了解耦。以官方的例子来说:

https://api.github.com/users/{user}/repos”中的{user}就是为了针对不同的github用户解耦。因为这里假设代入我的github,URL就将变成:

https://api.github.com/users/RawnHwang/repos”。而github的用户千千万万,如果使用我们之前的方式代码就会如下:
<code class="hljs ruby has-numbering" style="display: block; padding: 0px; background: transparent; color: inherit; box-sizing: border-box; font-family: "Source Code Pro", monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal;"><span class="hljs-variable" style="color: rgb(102, 0, 102); box-sizing: border-box;">@GET</span>(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"users/RawnHwang/repos"</span>)</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right: 1px solid rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li></ul><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right: 1px solid rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li></ul>


这二者的优劣一目了然,我们肯定不会想要为了获取不同的user的repos去写N多个套路完全相同的API - interface吧。

@Query

前面我们讲到:对于@GET来说,参数信息是可以直接放在url中上传的。那么你马上就反应过来了,这一样也存在严重的耦合!于是,就有了@query。



同样,为了便于理解,我们仍然自己来实际的使用一下。就用我们之前的举到的例子好了,这里我们用@query来替换我们之前说到的如下代码:
<code class="hljs ruby has-numbering" style="display: block; padding: 0px; background: transparent; color: inherit; box-sizing: border-box; font-family: "Source Code Pro", monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal;"><span class="hljs-variable" style="color: rgb(102, 0, 102); box-sizing: border-box;">@GET</span>(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"api/retrofitTesting?param=value"</span>)</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right: 1px solid rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li></ul><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right: 1px solid rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li></ul>


替换为:
<code class="hljs java has-numbering" style="display: block; padding: 0px; background: transparent; color: inherit; box-sizing: border-box; font-family: "Source Code Pro", monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal;"><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">public</span> <span class="hljs-class" style="box-sizing: border-box;"><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">interface</span> <span class="hljs-title" style="box-sizing: border-box; color: rgb(102, 0, 102);">DemoService</span> {</span>
<span class="hljs-annotation" style="color: rgb(155, 133, 157); box-sizing: border-box;">@GET</span>(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"api/retrofitTesting"</span>)
Call<ResponseInfo> testHttpGet(<span class="hljs-annotation" style="color: rgb(155, 133, 157); box-sizing: border-box;">@Query</span>(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"param"</span>) String param);
}</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right: 1px solid rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li></ul><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right: 1px solid rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li></ul>


调用的时候改为:
<code class="hljs sql has-numbering" style="display: block; padding: 0px; background: transparent; color: inherit; box-sizing: border-box; font-family: "Source Code Pro", monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal;"><span class="hljs-operator" style="box-sizing: border-box;"><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">Call</span><ResponseInfo> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">call</span> = service.testHttpGet(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"value"</span>);</span></code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right: 1px solid rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li></ul><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right: 1px solid rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li></ul>


然后就可以在服务器查看是否成功接收到参数了:
<code class="hljs cs has-numbering" style="display: block; padding: 0px; background: transparent; color: inherit; box-sizing: border-box; font-family: "Source Code Pro", monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal;">    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">public</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">void</span> <span class="hljs-title" style="box-sizing: border-box;">doGet</span>(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
System.<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">out</span>.println(request.getParameter(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"param"</span>));
}</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right: 1px solid rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li></ul><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right: 1px solid rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li></ul>


@QueryMap

聪明的你现在肯定还不满足,因为可能有这样的疑问:假设我要在参数中上传10个参数呢?这意味着我要在方法中声明10个@Query参数?当然不是!



我们看到了,Retrofit也考虑到了这点,所以针对于复杂的参数上传,为我们准备了@QueryMap。现在来修改我们自己的demo:
<code class="hljs cs has-numbering" style="display: block; padding: 0px; background: transparent; color: inherit; box-sizing: border-box; font-family: "Source Code Pro", monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal;"><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">public</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">interface</span> DemoService {
@GET(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"api/retrofitTesting"</span>)
Call<ResponseInfo> testHttpGet(@QueryMap Map<String,String> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">params</span>);
}</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right: 1px solid rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li></ul><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right: 1px solid rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li></ul>


调用的时候自然也发生了变化:
<code class="hljs lasso has-numbering" style="display: block; padding: 0px; background: transparent; color: inherit; box-sizing: border-box; font-family: "Source Code Pro", monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal;">        <span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">Map</span><span class="hljs-subst" style="color: rgb(0, 0, 0); box-sizing: border-box;"><</span><span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">String</span>,<span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">String</span><span class="hljs-subst" style="color: rgb(0, 0, 0); box-sizing: border-box;">></span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">params</span> <span class="hljs-subst" style="color: rgb(0, 0, 0); box-sizing: border-box;">=</span><span class="hljs-literal" style="color: rgb(0, 102, 102); box-sizing: border-box;">new</span> HashMap<span class="hljs-subst" style="color: rgb(0, 0, 0); box-sizing: border-box;"><></span>();
<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">params</span><span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">.</span>put(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"param1"</span>,<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"value1"</span>);
<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">params</span><span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">.</span>put(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"param2"</span>,<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"value2"</span>);
Call<span class="hljs-subst" style="color: rgb(0, 0, 0); box-sizing: border-box;"><</span>ResponseInfo<span class="hljs-subst" style="color: rgb(0, 0, 0); box-sizing: border-box;">></span> call <span class="hljs-subst" style="color: rgb(0, 0, 0); box-sizing: border-box;">=</span> service<span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">.</span>testHttpGet(<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">params</span>);</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right: 1px solid rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li></ul><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right: 1px solid rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li></ul>


@POST

有了之前的基础,现在我们免不了要捣鼓一下POST。相信有了@GET的使用经验,如果只是想发发简单的POST请求是没有多大的难度,我们关注下POST的BODY,即请求体的使用技巧。



通过官方文档,我们发现出现了一个新的东西叫做“@Body”,顾名思义它就是用来封装请求体的。而同时通过后面的“User”参数类型,我们不难推断出:使用@Body时,是通过实体对象的形式来进行封装的。那么闲话少说,我们当然仍旧是自己动手来试一下:

首先,我们编写一下servlet的doPost方法,假设我们这里提供一个新建User的API。完成后为该POST-request配置一个新的API URL,我们这里配置为:“/api/users”。然后,在Android端编写一个新的interface,大致如下:
<code class="hljs java has-numbering" style="display: block; padding: 0px; background: transparent; color: inherit; box-sizing: border-box; font-family: "Source Code Pro", monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal;"><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">public</span> <span class="hljs-class" style="box-sizing: border-box;"><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">interface</span> <span class="hljs-title" style="box-sizing: border-box; color: rgb(102, 0, 102);">DemoService</span> {</span>
<span class="hljs-annotation" style="color: rgb(155, 133, 157); box-sizing: border-box;">@POST</span>(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"api/users"</span>)
Call<ResponseInfo> uploadNewUser(<span class="hljs-annotation" style="color: rgb(155, 133, 157); box-sizing: border-box;">@Body</span> User user);
}

class User{
<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">private</span> String name;
<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">private</span> String gender;
<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">private</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">int</span> age;

<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">public</span> <span class="hljs-title" style="box-sizing: border-box;">User</span>(String name, String gender, <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">int</span> age) {
<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">this</span>.name = name;
<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">this</span>.gender = gender;
<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">this</span>.age = age;
}
}

class ResponseInfo{
String describe;
}</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right: 1px solid rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li><li style="box-sizing: border-box; padding: 0px 5px;">12</li><li style="box-sizing: border-box; padding: 0px 5px;">13</li><li style="box-sizing: border-box; padding: 0px 5px;">14</li><li style="box-sizing: border-box; padding: 0px 5px;">15</li><li style="box-sizing: border-box; padding: 0px 5px;">16</li><li style="box-sizing: border-box; padding: 0px 5px;">17</li><li style="box-sizing: border-box; padding: 0px 5px;">18</li><li style="box-sizing: border-box; padding: 0px 5px;">19</li><li style="box-sizing: border-box; padding: 0px 5px;">20</li></ul><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right: 1px solid rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li><li style="box-sizing: border-box; padding: 0px 5px;">12</li><li style="box-sizing: border-box; padding: 0px 5px;">13</li><li style="box-sizing: border-box; padding: 0px 5px;">14</li><li style="box-sizing: border-box; padding: 0px 5px;">15</li><li style="box-sizing: border-box; padding: 0px 5px;">16</li><li style="box-sizing: border-box; padding: 0px 5px;">17</li><li style="box-sizing: border-box; padding: 0px 5px;">18</li><li style="box-sizing: border-box; padding: 0px 5px;">19</li><li style="box-sizing: border-box; padding: 0px 5px;">20</li></ul>


这样其实就搞定了,是不是很简单。然后我们通过如下代码去调用测试就行了:
<code class="hljs sql has-numbering" style="display: block; padding: 0px; background: transparent; color: inherit; box-sizing: border-box; font-family: "Source Code Pro", monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal;"><span class="hljs-operator" style="box-sizing: border-box;"><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">Call</span><ResponseInfo> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">call</span> = service.uploadNewUser(new <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">User</span>(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"tsr"</span>,<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"male"</span>,<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">24</span>));</span></code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right: 1px solid rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li></ul><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right: 1px solid rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li></ul>


这里唯一需要说明的就是,通过@BODY这种方式封装请求体,Retrofit是通过JSON的形式来封装数据的。我们可以在服务器读取流中的数据打印:
<code class="hljs json has-numbering" style="display: block; padding: 0px; background: transparent; color: inherit; box-sizing: border-box; font-family: "Source Code Pro", monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal;">{"<span class="hljs-attribute" style="box-sizing: border-box;">name</span>":<span class="hljs-value" style="box-sizing: border-box;"><span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"tsr"</span></span>,"<span class="hljs-attribute" style="box-sizing: border-box;">gender</span>":<span class="hljs-value" style="box-sizing: border-box;"><span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"male"</span></span>,"<span class="hljs-attribute" style="box-sizing: border-box;">age</span>":<span class="hljs-value" style="box-sizing: border-box;"><span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">24</span></span>}</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right: 1px solid rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li></ul><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right: 1px solid rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li></ul>


我单独额外说明一下这个的初衷是因为:这种情况以servlet来说,通过如下的形式是读取不到的对应的参数值的(返回null),需要自己解析。
<code class="hljs avrasm has-numbering" style="display: block; padding: 0px; background: transparent; color: inherit; box-sizing: border-box; font-family: "Source Code Pro", monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal;">System<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.out</span><span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.println</span>(request<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.getParameter</span>(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"username"</span>))<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">;//输出为null</span></code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right: 1px solid rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li></ul><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right: 1px solid rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li></ul>


@FormUrlEncoded

这时有的朋友就说了,那我要是就想要通过request.getParameter的方式直接读取参数信息呢?没关系,也是可以的,使用@FormUrlEncoded搞定。



其实通过这个注解的命名,我们就很容易联系到HTTP Content-Type中的application/x-www-form-urlencoded:而其实在服务器打印Content-Type的话,会发现的确如此。也就是说,其实使用该注解过后,正是通过表单形式来上传参数的。
<code class="hljs java has-numbering" style="display: block; padding: 0px; background: transparent; color: inherit; box-sizing: border-box; font-family: "Source Code Pro", monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal;"><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">public</span> <span class="hljs-class" style="box-sizing: border-box;"><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">interface</span> <span class="hljs-title" style="box-sizing: border-box; color: rgb(102, 0, 102);">DemoService</span> {</span>
<span class="hljs-annotation" style="color: rgb(155, 133, 157); box-sizing: border-box;">@FormUrlEncoded</span>
<span class="hljs-annotation" style="color: rgb(155, 133, 157); box-sizing: border-box;">@POST</span>(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"api/users"</span>)
Call<ResponseInfo> uploadNewUser(<span class="hljs-annotation" style="color: rgb(155, 133, 157); box-sizing: border-box;">@Field</span>(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"username"</span>) String username,<span class="hljs-annotation" style="color: rgb(155, 133, 157); box-sizing: border-box;">@Field</span>(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"gender"</span>) String male,<span class="hljs-annotation" style="color: rgb(155, 133, 157); box-sizing: border-box;">@Field</span>(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"age"</span>) <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">int</span> age);
}</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right: 1px solid rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li></ul><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right: 1px solid rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li></ul>


然后是依旧是调用,这时服务器就可以通过request.getParameter直接读取参数了:
<code class="hljs sql has-numbering" style="display: block; padding: 0px; background: transparent; color: inherit; box-sizing: border-box; font-family: "Source Code Pro", monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal;"><span class="hljs-operator" style="box-sizing: border-box;"><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">Call</span><ResponseInfo> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">call</span> = service.uploadNewUser(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"tsr"</span>,<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"male"</span>,<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">24</span>);</span></code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right: 1px solid rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li></ul><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right: 1px solid rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li></ul>


当然,这个时候难免又会想起那个老梗:要写这么多的@Field参数?当然不是,也有@FieldMap供我们使用,使用方法参照@QueryMap

@Headers与@Header

使用了@FormUrlEncoded之后,不知道你有没有好奇一下,假设我们的参数中含有中文信息,会不会出现乱码?让我们来验证一下:
<code class="hljs sql has-numbering" style="display: block; padding: 0px; background: transparent; color: inherit; box-sizing: border-box; font-family: "Source Code Pro", monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal;"><span class="hljs-operator" style="box-sizing: border-box;"><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">Call</span><ResponseInfo> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">call</span> = service.uploadNewUser(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"张德帅"</span>,<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"male"</span>,<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">24</span>);</span></code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right: 1px solid rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li></ul><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right: 1px solid rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li></ul>


这里上传的username信息是中文,而在服务器读取后进行打印,其输出的是“?????·???”。没错,确实出现乱码了。

这个时候我们应该如何去解决呢?当然可以通过URLEncode对数据进行指定编码,然后服务器再进行对应的解码读取:
<code class="hljs avrasm has-numbering" style="display: block; padding: 0px; background: transparent; color: inherit; box-sizing: border-box; font-family: "Source Code Pro", monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal;">        String name =  URLEncoder<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.encode</span>(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"张德帅"</span>,<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"UTF-8"</span>)<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">;</span>
<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">Call</span><ResponseInfo> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">call</span> = service<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.uploadNewUser</span>(name,<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"male"</span>,<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">24</span>)<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">;</span></code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right: 1px solid rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li></ul><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right: 1px solid rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li></ul>


但如果了解一点HTTP协议的使用,我们知道还有另一种解决方式:在Request-Header中设置charset信息。于是,这个时候就涉及到添加请求头了:



关于@Headers的使用看上去非常简单。那么,接下来我们就来修改一下我们之前的代码:
<code class="hljs java has-numbering" style="display: block; padding: 0px; background: transparent; color: inherit; box-sizing: border-box; font-family: "Source Code Pro", monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal;"><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">public</span> <span class="hljs-class" style="box-sizing: border-box;"><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">interface</span> <span class="hljs-title" style="box-sizing: border-box; color: rgb(102, 0, 102);">DemoService</span> {</span>
<span class="hljs-annotation" style="color: rgb(155, 133, 157); box-sizing: border-box;">@Headers</span>(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"Content-type:application/x-www-form-urlencoded;charset=UTF-8"</span>)
<span class="hljs-annotation" style="color: rgb(155, 133, 157); box-sizing: border-box;">@FormUrlEncoded</span>
<span class="hljs-annotation" style="color: rgb(155, 133, 157); box-sizing: border-box;">@POST</span>(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"api/users"</span>)
Call<ResponseInfo> uploadNewUser(<span class="hljs-annotation" style="color: rgb(155, 133, 157); box-sizing: border-box;">@Field</span>(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"username"</span>) String username,<span class="hljs-annotation" style="color: rgb(155, 133, 157); box-sizing: border-box;">@Field</span>(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"gender"</span>) String male,<span class="hljs-annotation" style="color: rgb(155, 133, 157); box-sizing: border-box;">@Field</span>(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"age"</span>) <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">int</span> age);
}</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right: 1px solid rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li></ul><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right: 1px solid rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li></ul>


通过@Headers我们在Content-type中同时指明了编码信息,再次运行程序测试,就会发现服务器正确读取到了中文的信息。

除了@Headers之外,还有另一个注解叫做@Header。它的不同在于是动态的来添加请求头信息,也就是说更加灵活一点。我们也可以使用一下:
<code class="hljs java has-numbering" style="display: block; padding: 0px; background: transparent; color: inherit; box-sizing: border-box; font-family: "Source Code Pro", monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal;"><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">public</span> <span class="hljs-class" style="box-sizing: border-box;"><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">interface</span> <span class="hljs-title" style="box-sizing: border-box; color: rgb(102, 0, 102);">DemoService</span> {</span>
<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// @Headers("Content-type:application/x-www-form-urlencoded;charset=UTF-8")</span>
<span class="hljs-annotation" style="color: rgb(155, 133, 157); box-sizing: border-box;">@FormUrlEncoded</span>
<span class="hljs-annotation" style="color: rgb(155, 133, 157); box-sizing: border-box;">@POST</span>(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"api/users"</span>)
Call<ResponseInfo> uploadNewUser(<span class="hljs-annotation" style="color: rgb(155, 133, 157); box-sizing: border-box;">@Header</span>(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"Content-Type"</span>) String contentType,<span class="hljs-annotation" style="color: rgb(155, 133, 157); box-sizing: border-box;">@Field</span>(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"username"</span>) String username,<span class="hljs-annotation" style="color: rgb(155, 133, 157); box-sizing: border-box;">@Field</span>(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"gender"</span>) String male,<span class="hljs-annotation" style="color: rgb(155, 133, 157); box-sizing: border-box;">@Field</span>(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"age"</span>) <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">int</span> age);
}
<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// 调用</span>
Call<ResponseInfo> call = service.uploadNewUser(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"application/x-www-form-urlencoded;charset=UTF-8"</span>,<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"张德帅"</span>,<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"male"</span>,<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">24</span>);</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right: 1px solid rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li></ul><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right: 1px solid rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li></ul>



读取response header

通过上面的总结我们知道通过@Header可以在请求中添加header,那么我们如何去读取响应中的header呢?我们会发现官方文档并没有相关介绍。

那么显然我们就只能自己看看了,一找发现对于Retrofit2来说Response类有一个方法叫做headers(),通过它就获取了本次请求所有的响应头。

那么,我们记得在OkHttp里面,除了headers(),还有用于获取单个指定头的header()方法。我们能不能在Retrofit里使用这种方式呢?答案是可以。

我们发现Retrofit的Response还有一个方法叫做raw(),调用该方法就可以把Retrofit的Response转换为原生的OkHttp当中的Response。而现在我们就很容器实现header的读取了吧。
<code class="hljs avrasm has-numbering" style="display: block; padding: 0px; background: transparent; color: inherit; box-sizing: border-box; font-family: "Source Code Pro", monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal;">okhttp3<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.Response</span> okResponse = response<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.raw</span>()<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">;</span>
response<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.raw</span>()<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.header</span>(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"Cache-Control"</span>)<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">;</span>
}</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right: 1px solid rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li></ul><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right: 1px solid rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li></ul>



进阶技巧

@Multipart 与文件上传

在官方文档中,实际上还有一个重要的注解,那就是@Multipart。这个使用起来相对要复杂一点,所以放在这里。下面我们就来看一下这个东西的使用。



可以看到官方文档上对该注解使用的说明非常简单,但这个注解使用起来却不是那么简单,这就很烦人了。不过也没关系,我们由浅入深的来看一下。
<code class="hljs java has-numbering" style="display: block; padding: 0px; background: transparent; color: inherit; box-sizing: border-box; font-family: "Source Code Pro", monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal;"><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">public</span> <span class="hljs-class" style="box-sizing: border-box;"><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">interface</span> <span class="hljs-title" style="box-sizing: border-box; color: rgb(102, 0, 102);">DemoService</span> {</span>
<span class="hljs-annotation" style="color: rgb(155, 133, 157); box-sizing: border-box;">@Multipart</span>()
<span class="hljs-annotation" style="color: rgb(155, 133, 157); box-sizing: border-box;">@POST</span>(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"api/multipartTesting"</span>)
Call<ResponseInfo> testMultipart(<span class="hljs-annotation" style="color: rgb(155, 133, 157); box-sizing: border-box;">@Part</span>(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"part1"</span>) String part1,<span class="hljs-annotation" style="color: rgb(155, 133, 157); box-sizing: border-box;">@Part</span>(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"part2"</span>) String part2);
}</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right: 1px solid rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li></ul><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right: 1px solid rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li></ul>


这里对官方示例做了简化,因为我们在@Part参数中只使用了String类型,而没有声明RequestBody类型。接着就是调用它来进行测试:
<code class="hljs sql has-numbering" style="display: block; padding: 0px; background: transparent; color: inherit; box-sizing: border-box; font-family: "Source Code Pro", monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal;"><span class="hljs-operator" style="box-sizing: border-box;"><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">Call</span><ResponseInfo> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">call</span> = service.testMultipart(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"this is the part1"</span>,<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"this is the part2"</span>);</span></code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right: 1px solid rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li></ul><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right: 1px solid rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li></ul>


为了一探究竟,我们现在在服务器打印一下Content-Type与请求体(request-body)分别是怎样的:



现在我们来分析一下从打印的请求体中,我们能够得到哪些信息:

首先,本次请求的Content-Type是multipart/form-data; 也就是代表通过2进制形式上传多部分的数据。
boundary故名思议就是分割线,它是用来对上传的不同部分的数据来进行分隔的,就像上图中体现的一样。
通过@Part传入的参数信息都像上图中一样被组装,首先是相关的内容信息,然后间隔一个空行,之后是实际数据内容,最后接以boundary。
当使用@Part上传String参数信息时,我们可以看到其默认的参数类型为application/json。

(这代表如果你的服务器接不支持解析此类型的Content-Type,就需要自己修改为对应的类型)

现在我们注意到一个问题,那就是multipart/form-data将会以2进制形式来上传数据信息。那么,什么时候我们才需要2进制呢?显然就是文件的上传。

OK,那么我们继续修改代码,这次我们尝试通过@Part来上传一个文件会是什么情况?
<code class="hljs java has-numbering" style="display: block; padding: 0px; background: transparent; color: inherit; box-sizing: border-box; font-family: "Source Code Pro", monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal;"><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">public</span> <span class="hljs-class" style="box-sizing: border-box;"><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">interface</span> <span class="hljs-title" style="box-sizing: border-box; color: rgb(102, 0, 102);">DemoService</span> {</span>
<span class="hljs-annotation" style="color: rgb(155, 133, 157); box-sizing: border-box;">@Multipart</span>()
<span class="hljs-annotation" style="color: rgb(155, 133, 157); box-sizing: border-box;">@POST</span>(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"api/files"</span>)
Call<ResponseInfo> uploadFile(<span class="hljs-annotation" style="color: rgb(155, 133, 157); box-sizing: border-box;">@Part</span>(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"file"</span>) RequestBody photo);
}
<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">//调用部分</span>
File path = Environment.getExternalStorageDirectory();
File file = <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">new</span> File(path,<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"test.jpg"</span>);
RequestBody image = RequestBody.create(MediaType.parse(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"image/png"</span>),file);
Call<ResponseInfo> call = service.uploadFile(image);</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right: 1px solid rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li></ul><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right: 1px solid rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li></ul>


这里可以发现,当要上传的数据是文件时,就要使用到RequestBody了。再次运行程序,然后截取服务器打印的请求体的部分进行查看:



我们其实可以很直观的看到,大体的格式与之前都是一样的,而不同之处在于:

Content-Type不再是application/json,而是image/png了。
空行之后的数据内容不再是之前直观的文本,而是二进制的图片内容。

这个时候就会出现一个问题,假设我们为了方便,打算通过一些公有的API去测试一下上传文件(图片)什么的,会发现上传不成功。这是为什么呢?

实际上如果我们完全自己动手来写服务器,完全根据之前的请求体打印信息的格式来写解析的方法,肯定是也能完成文件上传的。但问题在于:

我们说到multipart/form-data是支持多部分数据同时上传的,于是就出现了一个听上去很有逼格的梗,叫做“图文混传”。那么:

为了区别于同一个request-body中的文本或文件信息,所以通常实际开发来说,上传文件的时候,Content-Disposition是这样的:
<code class="hljs lasso has-numbering" style="display: block; padding: 0px; background: transparent; color: inherit; box-sizing: border-box; font-family: "Source Code Pro", monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal;">Content<span class="hljs-attribute" style="box-sizing: border-box;">-Disposition</span>: form<span class="hljs-attribute" style="box-sizing: border-box;">-data</span>; name<span class="hljs-subst" style="color: rgb(0, 0, 0); box-sizing: border-box;">=</span><span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"file"</span>;filename<span class="hljs-subst" style="color: rgb(0, 0, 0); box-sizing: border-box;">=</span><span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"test.jpg"</span></code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right: 1px solid rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li></ul><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right: 1px solid rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li></ul>


而不是我们这里看到的:
<code class="hljs lasso has-numbering" style="display: block; padding: 0px; background: transparent; color: inherit; box-sizing: border-box; font-family: "Source Code Pro", monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal;">Content<span class="hljs-attribute" style="box-sizing: border-box;">-Disposition</span>: form<span class="hljs-attribute" style="box-sizing: border-box;">-data</span>; name<span class="hljs-subst" style="color: rgb(0, 0, 0); box-sizing: border-box;">=</span><span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"file"</span></code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right: 1px solid rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li></ul><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right: 1px solid rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li></ul>


于是别人的api里读取不到这个关键的“filename”,自然也就无法完成上传了。所以如果想通过Retrofit实现文件上传,可以通过如下方式来改造一下:
<code class="hljs java has-numbering" style="display: block; padding: 0px; background: transparent; color: inherit; box-sizing: border-box; font-family: "Source Code Pro", monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal;"><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">public</span> <span class="hljs-class" style="box-sizing: border-box;"><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">interface</span> <span class="hljs-title" style="box-sizing: border-box; color: rgb(102, 0, 102);">DemoService</span> {</span>
<span class="hljs-annotation" style="color: rgb(155, 133, 157); box-sizing: border-box;">@Multipart</span>()
<span class="hljs-annotation" style="color: rgb(155, 133, 157); box-sizing: border-box;">@POST</span>(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"api/files"</span>)
Call<ResponseInfo> uploadFile(<span class="hljs-annotation" style="color: rgb(155, 133, 157); box-sizing: border-box;">@Part</span>(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"file\";filename=\"test.jpg"</span>) RequestBody photo);
}</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right: 1px solid rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li></ul><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right: 1px solid rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li></ul>


然后我们在servlet服务器中进行解析,完成文件的上传。这里当然就不自己去写解析body的代码了,可以使用现有的库commons-fileupload。
<code class="hljs java has-numbering" style="display: block; padding: 0px; background: transparent; color: inherit; box-sizing: border-box; font-family: "Source Code Pro", monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal;">    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">public</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">void</span> <span class="hljs-title" style="box-sizing: border-box;">doPost</span>(HttpServletRequest request, HttpServletResponse response)
<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">throws</span> ServletException, IOException {
<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">try</span> {
DiskFileItemFactory factory = <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">new</span> DiskFileItemFactory();

ServletFileUpload upload = <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">new</span> ServletFileUpload(factory);

List<FileItem> items = upload.parseRequest(request);<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// 得到所有的文件</span>
Iterator<FileItem> i = items.iterator();
<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">while</span> (i.hasNext()) {
FileItem fi = (FileItem) i.next();
String fileName = fi.getName();
<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">if</span> (fileName != <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">null</span>) {
File fullFile = <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">new</span> File(fi.getName());
<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// 写入到D盘</span>
File savedFile = <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">new</span> File(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"D://"</span>, fullFile.getName());
fi.write(savedFile);
}
}
} <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">catch</span> (Exception e) {
e.printStackTrace();
}
}</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right: 1px solid rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li><li style="box-sizing: border-box; padding: 0px 5px;">12</li><li style="box-sizing: border-box; padding: 0px 5px;">13</li><li style="box-sizing: border-box; padding: 0px 5px;">14</li><li style="box-sizing: border-box; padding: 0px 5px;">15</li><li style="box-sizing: border-box; padding: 0px 5px;">16</li><li style="box-sizing: border-box; padding: 0px 5px;">17</li><li style="box-sizing: border-box; padding: 0px 5px;">18</li><li style="box-sizing: border-box; padding: 0px 5px;">19</li><li style="box-sizing: border-box; padding: 0px 5px;">20</li><li style="box-sizing: border-box; padding: 0px 5px;">21</li><li style="box-sizing: border-box; padding: 0px 5px;">22</li><li style="box-sizing: border-box; padding: 0px 5px;">23</li></ul><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right: 1px solid rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li><li style="box-sizing: border-box; padding: 0px 5px;">12</li><li style="box-sizing: border-box; padding: 0px 5px;">13</li><li style="box-sizing: border-box; padding: 0px 5px;">14</li><li style="box-sizing: border-box; padding: 0px 5px;">15</li><li style="box-sizing: border-box; padding: 0px 5px;">16</li><li style="box-sizing: border-box; padding: 0px 5px;">17</li><li style="box-sizing: border-box; padding: 0px 5px;">18</li><li style="box-sizing: border-box; padding: 0px 5px;">19</li><li style="box-sizing: border-box; padding: 0px 5px;">20</li><li style="box-sizing: border-box; padding: 0px 5px;">21</li><li style="box-sizing: border-box; padding: 0px 5px;">22</li><li style="box-sizing: border-box; padding: 0px 5px;">23</li></ul>


再次运行程序,从代码中可以看到,我们希望将客户端上传的图片保存电脑的D盘根目录下,打开D盘看一下吧,已经成功上传了!



不同类型的Converter

相信我们还记得之前我们读取服务器返回的json数据时,依赖于GsonConverterFactory就成功完成了解析。那么问题来了:

假设有的时候我们服务器返回的就是一段简单的文本信息呢?这叫老夫如何是好,其实这在之前就已经有了答案了:



我们看到除了基于GSON的converter之外,官方还提供了很多其它的Converter。眼尖的马上就看到了Scalars后面有一个东西叫做String。

于是接下来的工作就简单了,依然是配置依赖;然后将Call的泛型指定为String;最后记得将Converter改掉,像下面这样:
<code class="hljs r has-numbering" style="display: block; padding: 0px; background: transparent; color: inherit; box-sizing: border-box; font-family: "Source Code Pro", monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal;">//<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">...</span>
.addConverterFactory(ScalarsConverterFactory.create())</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right: 1px solid rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li></ul><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right: 1px solid rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li></ul>


再次运行程序,查看日志打印信息,发现成功搞定:



有了这个例子,对于同类型的需求我们就很容易举一反三了。但马上又想到:假设我们的数据类型官方没有提供现成的Converter呢?很简单,自己造!



从官方描述中,我们发现自定义Converter其实很简单。即创建一个继承自Converter.Factory的类,然后提供自己的Converter实例就行了。

那么假设,我们现在服务返回的数据格式是下面这样的。而我们的需求是希望在客户端对其解析后,将其放进一个Map里面。

username=张三&male=男性

根据这样的需求,我们可以像下面这样很容易的实现我们自己的Converter:
<code class="hljs axapta has-numbering" style="display: block; padding: 0px; background: transparent; color: inherit; box-sizing: border-box; font-family: "Source Code Pro", monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal;"><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">public</span> <span class="hljs-class" style="box-sizing: border-box;"><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">class</span> <span class="hljs-title" style="box-sizing: border-box; color: rgb(102, 0, 102);">CustomConverterFactory</span> <span class="hljs-inheritance" style="box-sizing: border-box;"><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">extends</span></span> <span class="hljs-title" style="box-sizing: border-box; color: rgb(102, 0, 102);">Converter</span>.<span class="hljs-title" style="box-sizing: border-box; color: rgb(102, 0, 102);">Factory</span>{</span>

<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">public</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">static</span> CustomConverterFactory create() {
<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">return</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">new</span> CustomConverterFactory();
}

@Override
<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">public</span> Converter<ResponseBody, ?> responseBodyConverter(Type type, Annotation[] annotations, Retrofit retrofit) {
<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">return</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">new</span> CustomConverter();
}

<span class="hljs-class" style="box-sizing: border-box;"><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">class</span> <span class="hljs-title" style="box-sizing: border-box; color: rgb(102, 0, 102);">CustomConverter</span> <span class="hljs-inheritance" style="box-sizing: border-box;"><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">implements</span></span> <span class="hljs-title" style="box-sizing: border-box; color: rgb(102, 0, 102);">Converter</span><<span class="hljs-title" style="box-sizing: border-box; color: rgb(102, 0, 102);">ResponseBody</span>,<span class="hljs-title" style="box-sizing: border-box; color: rgb(102, 0, 102);">Map</span><<span class="hljs-title" style="box-sizing: border-box; color: rgb(102, 0, 102);">String</span>,<span class="hljs-title" style="box-sizing: border-box; color: rgb(102, 0, 102);">String</span>>>{</span>

@Override
<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">public</span> Map<String,String> convert(ResponseBody body) throws IOException {
Map<String,String> map = <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">new</span> HashMap<>();
String content = body.string();
String [] keyValues = content.split(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"&"</span>);

<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">for</span> (<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">int</span> i = <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>;i<keyValues.length;i++){
String keyValue = keyValues[i];
<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">int</span> postion = keyValue.indexOf(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"="</span>);
String key  = keyValue.substring(<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>,postion);
String value = keyValue.substring(postion+<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">1</span>,keyValue.length());
map.put(key,value);
}
<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">return</span> map;
}
}
}</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right: 1px solid rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li><li style="box-sizing: border-box; padding: 0px 5px;">12</li><li style="box-sizing: border-box; padding: 0px 5px;">13</li><li style="box-sizing: border-box; padding: 0px 5px;">14</li><li style="box-sizing: border-box; padding: 0px 5px;">15</li><li style="box-sizing: border-box; padding: 0px 5px;">16</li><li style="box-sizing: border-box; padding: 0px 5px;">17</li><li style="box-sizing: border-box; padding: 0px 5px;">18</li><li style="box-sizing: border-box; padding: 0px 5px;">19</li><li style="box-sizing: border-box; padding: 0px 5px;">20</li><li style="box-sizing: border-box; padding: 0px 5px;">21</li><li style="box-sizing: border-box; padding: 0px 5px;">22</li><li style="box-sizing: border-box; padding: 0px 5px;">23</li><li style="box-sizing: border-box; padding: 0px 5px;">24</li><li style="box-sizing: border-box; padding: 0px 5px;">25</li><li style="box-sizing: border-box; padding: 0px 5px;">26</li><li style="box-sizing: border-box; padding: 0px 5px;">27</li><li style="box-sizing: border-box; padding: 0px 5px;">28</li><li style="box-sizing: border-box; padding: 0px 5px;">29</li><li style="box-sizing: border-box; padding: 0px 5px;">30</li></ul><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right: 1px solid rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li><li style="box-sizing: border-box; padding: 0px 5px;">12</li><li style="box-sizing: border-box; padding: 0px 5px;">13</li><li style="box-sizing: border-box; padding: 0px 5px;">14</li><li style="box-sizing: border-box; padding: 0px 5px;">15</li><li style="box-sizing: border-box; padding: 0px 5px;">16</li><li style="box-sizing: border-box; padding: 0px 5px;">17</li><li style="box-sizing: border-box; padding: 0px 5px;">18</li><li style="box-sizing: border-box; padding: 0px 5px;">19</li><li style="box-sizing: border-box; padding: 0px 5px;">20</li><li style="box-sizing: border-box; padding: 0px 5px;">21</li><li style="box-sizing: border-box; padding: 0px 5px;">22</li><li style="box-sizing: border-box; padding: 0px 5px;">23</li><li style="box-sizing: border-box; padding: 0px 5px;">24</li><li style="box-sizing: border-box; padding: 0px 5px;">25</li><li style="box-sizing: border-box; padding: 0px 5px;">26</li><li style="box-sizing: border-box; padding: 0px 5px;">27</li><li style="box-sizing: border-box; padding: 0px 5px;">28</li><li style="box-sizing: border-box; padding: 0px 5px;">29</li><li style="box-sizing: border-box; padding: 0px 5px;">30</li></ul>


现在,我们就可以进行调用测试了:
<code class="hljs lasso has-numbering" style="display: block; padding: 0px; background: transparent; color: inherit; box-sizing: border-box; font-family: "Source Code Pro", monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal;">            <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">public</span> <span class="hljs-literal" style="color: rgb(0, 102, 102); box-sizing: border-box;">void</span> onResponse(Call<span class="hljs-subst" style="color: rgb(0, 0, 0); box-sizing: border-box;"><</span><span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">Map</span><span class="hljs-subst" style="color: rgb(0, 0, 0); box-sizing: border-box;"><</span><span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">String</span>,<span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">String</span><span class="hljs-subst" style="color: rgb(0, 0, 0); box-sizing: border-box;">>></span> call, Response<span class="hljs-subst" style="color: rgb(0, 0, 0); box-sizing: border-box;"><</span><span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">Map</span><span class="hljs-subst" style="color: rgb(0, 0, 0); box-sizing: border-box;"><</span><span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">String</span>,<span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">String</span><span class="hljs-subst" style="color: rgb(0, 0, 0); box-sizing: border-box;">>></span> response) {
<span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">Map</span><span class="hljs-subst" style="color: rgb(0, 0, 0); box-sizing: border-box;"><</span><span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">String</span>,<span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">String</span><span class="hljs-subst" style="color: rgb(0, 0, 0); box-sizing: border-box;">></span> <span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">map</span> <span class="hljs-subst" style="color: rgb(0, 0, 0); box-sizing: border-box;">=</span> response<span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">.</span>body();
<span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">Set</span><span class="hljs-subst" style="color: rgb(0, 0, 0); box-sizing: border-box;"><</span><span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">String</span><span class="hljs-subst" style="color: rgb(0, 0, 0); box-sizing: border-box;">></span> keySet <span class="hljs-subst" style="color: rgb(0, 0, 0); box-sizing: border-box;">=</span> <span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">map</span><span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">.</span>keySet();

for (<span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">String</span> key : keySet){
<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">Log</span><span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">.</span>d(<span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">TAG</span>,key<span class="hljs-subst" style="color: rgb(0, 0, 0); box-sizing: border-box;">+</span><span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">":"</span><span class="hljs-subst" style="color: rgb(0, 0, 0); box-sizing: border-box;">+</span><span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">map</span><span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">.</span>get(key));
}

}</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right: 1px solid rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li></ul><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right: 1px solid rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li></ul>


查看日志打印:



使用Interceptor

之前在学习@Headers的用法的时候,其实官方文档中还有一个东西,我们没有总结。官方的描述是这样的:

Headers that need to be added to every request can be specified using an OkHttp interceptor.

简单易懂,也就是说:如果你项目里的每一个请求需要加入某个header,那么就可以使用interceptor(interceptor本身是OkHttp里的东西)

interceptor顾名思义就是拦截器,其具体使用方法可以参照https://github.com/square/okhttp/wiki/Interceptors。这里我们看下官方的第一个例子:



这里面的其它东西相信都很熟悉,一个新的关键叫做Interceptor.chain。很明显,从命名我们可以猜想出它就是完成拦截的关键。

事实上,我们可以对以上的示例进行简化,最后其实我们需要学习的就两行代码:
<code class="hljs vbscript has-numbering" style="display: block; padding: 0px; background: transparent; color: inherit; box-sizing: border-box; font-family: "Source Code Pro", monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal;"><span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">Request</span> <span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">request</span> = chain.<span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">request</span>();
<span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">Response</span> <span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">response</span> = chain.proceed(<span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">request</span>);</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right: 1px solid rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li></ul><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right: 1px solid rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li></ul>


也就是说:

通过chain的request()方法,可以返回Request对象。
通过chain的proceed()方法,可以返回此次请求的响应对象。

那么,以我们之前的需求来说:对所有的请求都添加某个请求头。实际就很容易实现了。
<code class="hljs java has-numbering" style="display: block; padding: 0px; background: transparent; color: inherit; box-sizing: border-box; font-family: "Source Code Pro", monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal;">            <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">public</span> okhttp3.Response <span class="hljs-title" style="box-sizing: border-box;">intercept</span>(Chain chain) <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">throws</span> IOException {
Request request = chain.request();
<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// 重写request</span>
Request requestOverwrite = request.newBuilder().header(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"User-Agent"</span>,<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"Android"</span>).build();

<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">return</span> chain.proceed(requestOverwrite);
}</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right: 1px solid rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li></ul><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right: 1px solid rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li></ul>


同理,如果我们想要在每个Response中都添加某个header值呢?做法是一样的:
<code class="hljs avrasm has-numbering" style="display: block; padding: 0px; background: transparent; color: inherit; box-sizing: border-box; font-family: "Source Code Pro", monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal;">            @Override
public okhttp3<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.Response</span> intercept(Chain chain) throws IOException {
Request request = chain<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.request</span>()<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">;</span>
okhttp3<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.Response</span> originalResponse = chain<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.proceed</span>(request)<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">;</span>

return originalResponse<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.newBuilder</span>()<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.header</span>(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"Cache-Control"</span>,<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"max-age=100"</span>)<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.build</span>()<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">;</span>
}</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right: 1px solid rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li></ul><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right: 1px solid rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li></ul>


但是,到现在为止,我们说到的都是interceptor在OkHttp中的使用。那么对应在Retrofit呢,其实很简单,因为我们说了Retrofit就是基于OkHttp的。

那么,前面一切的步骤都可以按照在OkHttp里的使用方法按部就班。唯一额外要做的工作就是,构建好OkHttpClient对象后,记得把它设置给Retrofit。
<code class="hljs avrasm has-numbering" style="display: block; padding: 0px; background: transparent; color: inherit; box-sizing: border-box; font-family: "Source Code Pro", monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal;">        Retrofit retrofit = new Retrofit<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.Builder</span>()
<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.baseUrl</span>(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"http://192.168.2.100:8080/TestServer/"</span>)
<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.client</span>(mOkHttpClinet) // 看这里,看这里
<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.build</span>()<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">;</span></code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right: 1px solid rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li></ul><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right: 1px solid rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li></ul>



总结

到了这里,对Android中常用的网络请求库say hello系列的三篇博客总算是总结完毕了。而针对Retrofit的此文是写的最认真的一篇,一个是因为现在它的确是流行;其次是因为个人也比较感兴趣。如果您观看后有任何想法,望多多指正,给出宝贵意见。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  Android Retrofit