Retrofit 并不能说是一个网络请求库,它只是一个网络请求库的封装库,在其内部网络请求是直接交给 OkHttp 完成的,与 Volley 相比,OkHttp 缺乏了一些更人性化的功能,它更多地专一于如何把一个网络请求作好,因此在使用 OkHttp 进行请求的时候,咱们要本身生成一个 Request,再自行处理 Response 成咱们须要的数据格式。好像是为了弥补这一缺点,Square 又基于 OkHttp 给出了一个封装库,Retrofit ,Retrofit 的出现,直接将 OkHttp 的使用体验提高了几个档次,使用 Retrofit 进行网络请求,咱们将不会再看到 Request 、Response ,咱们声明一个方法,就表明了一个 Request ,而这个方法的返回数据,就是咱们想要的 Response 。 这种方式改变了原始意义上的网络请求,用户再也不关心什么 Request 和 Response ,而是这个网络请求须要什么参数,又会给出什么结果。 为了实现以调用方法替代构建 Request 的功能,Retrofit 大量使用了注解。好比,一个网络请求方法能够声明以下:设计模式
interfaceAPI{ @GET("demo/") Call<String>getDemo(@Query("id") id); }复制代码
如上所示,表明一个 GET 请求,请求地址为 demo/,请求参数为id=?
。而在这个例子中,使用到了两个注解,分别是 GET 和 Query ,分别表明 GET 方法和 Query 字段。Retrofit 提供的注解类型还远不止如此,足够支持绝大部分的网络请求。数组
Retrofit 类是使用的入口,其create()
方法用于建立一个实例,而构建 Retrofit 实例使用了 Build 模式,Build 给 Retrofit 的实例化提供参数。 构造方法参数:安全
okhttp3.Call.Factory,okhttp 的类,默认是 OkhttpClient ,只有一个方法,newCall()
。bash
HttpUrl,okhttp 中的类,表示一个 Urlmarkdown
List<Converters.Factory>,Converter.Factory 集,用户自定义若干 + 内建的 BuiltInConverters 。Converter 基本功能,类型转换器,Factory 提供有三种转换方式,? -> RequestBody ResponseBody -> ? ? -> String,从转换双方类型即可以看出,第一种,将任意一种类型转换为 RequestBody ,是为在发起请求的时候,将用户所给的参数类型转换为标准的请求格式,第二种就是将网络请求以后获得的标准的返回格式转换为其余任意类型,第三种,讲任意类型转换为 String,也用于在网络请求的时候转换。网络
List<CallAdapter.Factory>,CallAdapter.Factory 集,用户自定义若干 + 默认的,CallAdapter ,Call 适配器,可用于将 Call 类型转换为其余任意类型,API 方法默认返回是 Call<ResponseBody> 类型,经过 Converter 能够将其转换为 Call<String> Call<JsonObject> 格式,可是不能改变 Call 自己,CallAdapter 就是用于解决这个问题,它能够将 Call<ResponseBody> 转换为 Future<String> 格式。因此,在 Converter 的 ResponseBody -> ? 这一阶段,彻底是能够经过 CallAdapter 直接实现的。app
Executor,回调处理器,异步
boolean validateEagerly,是否在建立请求类实例时就加载全部的方法,默认状况是第一次调用时才会加载ide
建立自定义的代理类,经过重写方法调用的逻辑,一方面将原生的方法依旧调用,一方面将对应 API 的方法解析成网络请求的格式。 先将 API 方法解析成 ServiceMethod ,而后再交给 OkHttpCall 处理。ui
运行时经过反射解析方法,并将已经解析过的方法加入 serviceMethodCache ,从中取 ServiceMethod 的时候使用了双重检测保证线程安全。 不然就调用 ServiceMethod 的 Build 构建出一个实例。Build 完成了解析 Method 的工做,须要先获得一些 Method 相关的信息,主要的信息有:
Method 的返回类型
Method 的全部注解
Method 的全部参数,包括其数据类型和全部的所有注解 一个方法的默认返回类型应该是 Call<ResponseBody> 类型,因此若是用户不使用自定义的 CallAdapter 和 Converter ,就只能声明返回类型为这个的方法,经过自定义 Converter ,能够将 Call<ResponseBody> 转换为 Call<String>,即将 ResponseBody 转换为 Converter ,而使用自定义 CallAdapter ,则能够直接将 Call<ResponseBody> 转换为 Future<String> 。 因此,Method 返回类型的主要做用就是用于查找对应的 CallAdapter ,Retrofit 经过工厂类生成 CallAdapter ,因此须要像 Retrofit 中加入自定义的工厂类,工厂类使用public abstract @Nullable CallAdapter<?, ?> get(Type returnType, Annotation[] annotations,Retrofit retrofit);
方法生成 CallAdapter ,Factory 经过这个方法提供的三个参数选择一个合适的 CallAdapter 返回,如 returnType 是 Future<String> ,则须要生成一个将 Call<?> 转换为 Future<String> 的 CallAdapter 。 再说 CallAdapter ,它的主要方法是T adapt(Call<R> call)
,其中 Call<R> 是原始的类型,T 就是输出的类型,以上面为例,R 就是 String ,T 是 Future<String> 。但上面说到过,方法的默认返回类型是 Call<ResponseBody> ,那为什么此处输入类型倒是 Call<R> ?为何 ResponseBody 会变成一个泛型,这里则是因为 Converter 存在的缘由。 上面说到过,Converter 能够将 Call<ResponseBody> 转换成 Call<String> ,那么天然也能够将其转换成任意类型,即 Call<R>,因此在 ServiceMethod.Build 的build()
方法中,前后建立了 CallAdapter 和 Converter ,而此处也说明了一个问题,那就是 Converter 会先于 CallAdapter 执行,CallAdapter 的执行依赖于 Converter 的执行,或者说,CallAdapter 的输入就是 Converter 的输出。 Converter 在两个位置执行,一是enqueue()
方法,一是excute()
方法,都是在获得原始的网络请求结果以后马上调用的,而 CallAdapter 的adapt()
方法倒是在生成调用方法以后生成 Call 的时候调用,如此看来应该是 CallAdapter 先于 Converter 工做的。从这个逻辑上讲确实,可是此刻 CallAdapter 中的 Call 却并无获得数据,CallAdapter 最终的目的只是转换 Call ,以下一个转换为 Future 的例子:
@OverridepublicCompletableFuture<R>adapt(finalCall<R>call) { finalCompletableFuture<R>future=newCompletableFuture<R>() { @Overridepublicbooleancancel(booleanmayInterruptIfRunning) { if(mayInterruptIfRunning) { call.cancel(); } returnsuper.cancel(mayInterruptIfRunning); } }; call.enqueue(newCallback<R>() { @OverridepublicvoidonResponse(Call<R>call, Response<R>response) { if(response.isSuccessful()) { future.complete(response.body()); } else{ future.completeExceptionally(newHttpException(response)); } } @OverridepublicvoidonFailure(Call<R>call, Throwablet) { future.completeExceptionally(t); } }); returnfuture; }复制代码
Future 仍是在 Call 获取数据以后再对结果进行转递,而在调用future.complete(response.body())
之时,Converter 的convert()
方法已经执行了,因此这里的 R ,就是将 ResponseBody 转换以后的结果,从这个角度而言,依旧是 Converter 先执行。
因此,CallAdapter 的数据依赖于 Converter 执行的结果,那么为了保证 CallAdapter 的输入类型与 Converter 的输出一致,CallAdapter 提供了另外一个抽象方法,Type responseType()
,这里返回了一个类型,能够将其理解为 CallAdapter 须要的输入数据类型,而以后建立 Converter 实例的时候,就是根据这个类型查找 Converter.Factory ,继而生成 Converter ,两者之间的一致性就能够由此保证。以上是解析 Method 的第一步,接着会解析 Method 的注解,通常就是声明了请求方法,GET、POST 等,调用的是parseMethodAnnotation()
方法。再接着就是解析 Method 的全部参数,根据参数的数据类型和注解生成 ParameterHandler 实例,调用parseParameter()
方法。解析的逻辑是比较有意思的,对于一个参数,先判断注解类型,好比是 Quey 、Filed、Path 或 QueryMap 等,不一样的类型会生成不一样的 ParameterHandler ,好比 Query ,须要先根据 Query 这个注解对应的参数的类型,查找到一个 Converter ,使得可以将这个参数转换为 String 类型,由于 Query 就应该是一个 String ,若是不是,须要有 Converter 将其转成 String 。完了以后,便会生成一个 ParameterHandler 实例,ParameterHandler 是一个抽象类,它有许多的子类,并且每个子类对应着一种注解类型,如 ParameterHandler.Query 这个子类就是用于处理 Query 这个注解的,它实现的apply()
方法,可以将参数转换成 ResquestBuilder 中的一个 Query ,以下:
@Overridevoidapply(RequestBuilderbuilder, @NullableTvalue) throwsIOException{ if(value==null) return; // Skip null values. StringqueryValue=valueConverter.convert(value); if(queryValue==null) return; // Skip converted but null values builder.addQueryParam(name, queryValue, encoded); }复制代码
另外,ParameterHandler 还有iterable()
和array()
方法,可用于处理链表、数组等数据,
finalParameterHandler<Iterable<T>>iterable() { returnnewParameterHandler<Iterable<T>>() { @Overridevoidapply(RequestBuilderbuilder, @NullableIterable<T>values) throwsIOException{ if(values==null) return; // Skip null values. for(Tvalue: values) { ParameterHandler.this.apply(builder, value); } } }; }复制代码
其本质是重写其apply()
方法,在这个方法里面先遍历 iterable ,再调用实际的apply()
方法写到 RequestBuilder 中。 当全部参数的 ParameterHandler 生成完了以后,ServiceMethod 也就算建立好了。接下来即是建立一个 Call 返回。
接下来将 ServiceMethod 做为参数构建 OkHttpCall 实例,OkHttpCall 实现了 Call 接口,封装了 okhttp.Call ,okhttp.Call 的实例会在发起网络请求的时候,由 ServiceMathod 建立,SeriviceMethod 则利用存储在其内部的各类参数,如 Url、ParameterHandler 等构建出 RequestBuilder ,再由 OkHttpClient 建立出 okhttp.Call 实例返回。 OkHttpCall 实现的是 Call 接口,调用方法的最后一步,就是将 Call<ResponseBody> 由 CallAdapter 转换成方法的实际返回类型,Retrofit 有一个默认的 CallAdapter ,它的adapt()
方法的实现就是什么都不作,直接将 Call 返回。这也就解释了为何,若是没有加入自定义 CallAdapter ,方法的返回类型就必须是 Call<?> 。 还有一点,默认的 CallAdapter 并非什么都没作,它将 enqueue()
的 Callback 的回调切换到了主线程执行,由于在 OkHttp 中调用的enqueue()
会将请求放在线程池里执行。 由此,一个网络请求就建立完成了,下一步是执行网络请求。
就以默认状况下返回的 Call<ResponseBody> 为例,Call 中声明了一些网络请求的方法,如enqueue()
、execute()
,这些方法会调用 okhttp.Call 的对应方法,好比
call.enqueue(newokhttp3.Callback() { @OverridepublicvoidonResponse(okhttp3.Callcall, okhttp3.ResponserawRespon Response<T>response; try{ response=parseResponse(rawResponse); } catch(Throwablee) { callFailure(e); return; } try{ callback.onResponse(OkHttpCall.this, response); } catch(Throwablet) { t.printStackTrace(); } } @OverridepublicvoidonFailure(okhttp3.Callcall, IOExceptione) { callFailure(e); } privatevoidcallFailure(Throwablee) { try{ callback.onFailure(OkHttpCall.this, e); } catch(Throwablet) { t.printStackTrace(); } } });复制代码
Call 有两种网络请求方式,分别对应同步和异步请求,若是是同步请求,就会直接返回一个 Response<T> ,若是是异步请求,则还须要借助回调类 Callback 完成。
Retrofit 将 OkHttp 返回的数据进一步包装获得 Response<T> ,包装使用的方法就是parseResponse()
,内部逻辑为,先获得 okhttp.Response 的 ResponseBody ,再调用 Converter 将 ResponseBody 转换为其它类型。
以上是 Retrofit 一个网络请求的所有流程。 在代码里,Retrofit 使用了许多设计模式,例如适配器模式(CallAdapter,Converter,ParameterHandler.iterable()),工厂模式(CallAdapter.Factory、Converter.Factory),代理模式(解析 Method 的时候,使用Proxy.newProxyInstance()
生成了一个代理实例,自定义的方法才去了自定义的执行模式),Build 模式(Retrofit.Build、ServiceMethod.Build),单例模式(BuiltInConverters.ToStringConverter),策略模式(ParameterHandler.Query…)。 除此,充分利用 Java 注解也是 Retrofit 一大特点,Retrofit 使用了一个 Method 全部能够利用的地方,方法注解、方法参数、参数注解甚至参数类型、返回类型,都被 Retrofit 加以利用,其余较多使用注解的库好比 EventBus、ButterKnife ,也有与之相似的一些效果。 从一个封装库的角度来讲,Retrofit 是一个比较成功的库,用户能够经过加入自定义的 CallAdapter 和 Converter ,将网络请求方法的返回类型设置为任何所需的,而且这些并不须要用户本身写,Retrofit 有已经写好的适配器,将其加入到项目中便可使用。即使用户不想使用自定义的,光是将方法转换为 Request 的功能也值得一用了。 惟一不足的,我认为是 Retrofit 只能使用 OkHttp 做为内在的网络请求库,Retrofit 的实现也在不少地方依赖于 OkHttp ,虽然 Retrofit 可能就是做为 OkHttp 的封装库而存在的,但我以为 Retrofit 不该止步于此。