众所周知,Retrofit是OkHttp的封装,APP对网络交互部分的完结根本上都是RxJava+Retrofit+OkHttp架构(或协程+Retrofit+OkHttp),可以说,Retrofit现已广为人知。本文首要介绍Retrofit主线源码完结机制,及其所选用的规划形式所涉及到的思维等等。

OKHttp 的运用缺点

这儿说的运用缺点是不那么便当的当地:

1)用户网络恳求的接口装备繁琐,尤其是需求装备杂乱恳求body,恳求头,参数的时分;
2)数据解析进程需求用户手动拿到responsbody进行解析,不能复用;
3)无法适配主动进行线程的切换;
4)万一咱们的存在嵌套网络恳求就会堕入“回调陷阱”。

Retrofit首要处理的问题

在OkHttp运用如此繁琐的情况下,更方便运用的Retrofit应运而生。其所处理的OkHttp的缺点问题包含两方面:

①恳求前:完结共同装备的网络恳求头,共同适配恳求request。
②成果回来:retrofit完结数据适配、线程切换。

简略运用

(本段文字仅讲述retrofit的根本用法,假设对其用法以及掌握的老铁可以直接跳过,检查源码解析部分。)

1、增加依靠

implementation'com.squareup.retrofit2:retrofit:2.9.0'
implementation'com.squareup.retrofit2:converter-gson:2.9.0'

2、界说网络服务接口

增加依靠并同步后,创立一个接口,专门担任界说网络API。这儿咱们选用接口是用于

调试Github的敞开API,接口为:api.github.com/users/octoc… 在恳求后会获取Github用户Octocat的Repo列表:

Retrofit源码精析
复制其数据,用AS的GsonFormat主动生成Javabean:

Retrofit源码精析
在这儿需求留意这个接口的Json数据是以中括号{开端,是一个Json字符串数组,即对应的JavaBean是一个List,这儿生成的Repo是这个List中元素对应的数据结构。对此咱们可以界说获取此数据接口。

public interfaceNetService {
@GET("users/{user}/repos") //装备Get恳求、URL路径  
Call<List<Repo>>getRepos(@Path("user") String user); //指定回来Call<T>方针,这儿的T指定网络解析数据后回来的类型  
//@Path("user")表明参数user会替换URL路径中的{user}  
}

3、在AndroidManifest.xml中增加网络权限:

<uses-permissionandroid:name="android.permission.INTERNET"/>

4、完结网络服务接口

创立好接口后,接下来便是用Retrofit完结此接口恳求逻辑:

Retrofit retrofit =newRetrofit.Builder()
.baseUrl("https://api.github.com") //装备URL的基地址  
.addConverterFactory(GsonConverterFactory.*create*())//装备Gson转化器  
.build();  
NetService netService = retrofit.create(NetService.class); //用Retrofit方针回来一个NetService的完结  
Call<List<Repo>> octocat = netService.getRepos("octocat"); //获取Call方针,用该方针的enqueue完结异步恳求  
octocat.enqueue(newCallback<List<Repo>>() {  
@Override  
public voidonResponse(Call<List<Repo>> call,Response<List<Repo>> response) {  
for(Repo rp : response.body()){  
Log.i(TAG,"get the id:"+(rp.getId())); //获取数据后打印ID  
}  
}  
@Override  
public voidonFailure(Call<List<Repo>> call,Throwable t) {  
Log.i(TAG,"onFailure:"+(t.toString()));  
}  
});

运转后可见打印的日志:

Retrofit源码精析
至此,完整的一次网络恳求成功了。当然,Retrofit还可以进行更多的杂乱操作,如装备恳求头、恳求提、表单提交等,更多办法可参考square.github.io/retrofit/。

源码流程图

下面是调用Retrofit做一次网络恳求的代码流程:

Retrofit源码精析

动态署理

Retrofit源码中运用了动态署理,在看源码之前咱们有必要先了解。在某些场景下,咱们要用某些功用,但不是直接调用完结类,而是经过署理类来完结的。经过署理,咱们可以躲藏完结类的细节,在不修改完结类的基础之上,增加额外的功用等。在日常日子中,署理形式处处可见,例如房屋中介、二手车贩子、代购等等。咱们所说的署理,一般是指静态署理,即一个完结类对应一个署理类,彼此一一对应。假设你现在是个大型轮胎制造商,有家轿车公司预备在你这儿订货车轮胎,咱们用代码完结下:

首要,完结个接口,表明咱们要做的事情——造轮胎:

public interfaceWheel {
voidproduce();  
}

然后完结这个接口:

public classWheelMakerimplementsWheel{
@Override  
public voidproduce() {  
Log.i("proxyDemo","造好并装上车轮");  
}  
}

独自的车轮是没有用的,这个时分轿车厂商就来了,要把车轮装上去,轿车厂商完结代码如下:

public classBenZimplementsWheel{
privateWheelwheel;  
publicBenZ(Wheel wheel){  
this.wheel= wheel;  
}  
@Override  
public voidproduce() {  
before();  
wheel.produce();  
after();  
}  
private voidafter() {  
Log.i("proxyDemo","BenZ整车拼装结束,可以售卖了");  
}  
private voidbefore() {  
Log.i("proxyDemo","BenZ拼装好其他零件,只缺装轮胎了");  
}  
}

轿车厂商来了,拿走了轮胎,就下来便是拼装了,拼装好就可以售卖,然后才有钱回款给你,你公司才能赚钱,代码如下:

Log.*i*("proxyDemo","--------------静态署理-------------");  
Wheel wheel =newWheelMaker();  
BenZ benZ =newBenZ(wheel);  
benZ.produce();

轿车公司拿着你给的轮胎接口后进行拼装,然后售卖,代码很简略没必要过多解释了。对应履行后对应输出如下:

Retrofit源码精析
随着日积月累,你越做越大,军方来找你做坦克的车轮。你咬咬牙,接了这笔订单。因为军方车轮规格要求更严,对应的,你重新安排了一条出产线接口,做特别轮胎:

public classSpecialWheelMakerimplementsWheel{
@Override  
public voidproduce() {  
Log.i("proxyDemo","造好特别车轮并装上-");  
}  
}

听说你造好后,军方来人,拿走你的轮胎回去拼装并给了你项目回款:

public classTankimplementsWheel{
privateSpecialWheelMakerspecialWheelMaker;  
publicTank(SpecialWheelMaker specialWheelMaker){  
this.specialWheelMaker= specialWheelMaker;  
}  
@Override  
public voidproduce() {  
before();  
specialWheelMaker.produce();  
after();  
}  
private voidafter() {  
Log.i("proxyDemo","Tank拼装结束,预备上战场了");  
}  
private voidbefore() {  
Log.i("proxyDemo","Tank拼装好其他零件,只缺装轮胎了");  
}  
}

拼装结束那天,军方邀请你去观赏,所以你一边叮咛手下人持续做事,一边前去观赏,代码如下:

Log.i("proxyDemo","--------------轿车的静态署理-------------");
Wheel wheel = new WheelMaker();
BenZ benZ = new BenZ(wheel);
benZ.produce();
Log.i("proxyDemo","--------------Tank的静态署理-------------");
SpecialWheelMaker specialWheelMaker = new SpecialWheelMaker();
Tank tank = new Tank(specialWheelMaker);
tank.produce();

对应输出为:

Retrofit源码精析
你很开心,因为随着这些项目的顺畅落地,你的名声越来越大,很多轿车厂商找上门来协作,但你也发现,本钱太高(代码臃肿)了。什么别摸我、玛傻拉弟弟轮胎都简直相同,除了单个细节不相同外,如此为何还要给他们各个品牌之间独立的署理?22世纪了,早就没有中间商赚差价了,所以你自问自答,一套工业流程,能不能署理一切厂商制造署理呢?答案是必定的。另外,从代码的视点上来看,假设新增一个厂商,就又要新加一个署理类,代码量会不停增加,而在署理类中的before()和after()都是重复的,不能复用。从某种方面来说,这就不属于好代码了。

这儿就需求用到动态署理了。动态署理不需求事先创立署理(轿车厂商)类,而是依据需求动态创立。相当于一个工厂流水线,对应不同种类型轮胎产品,不管轮胎类型数量增加多少,出产线只要一个。从代码的视点来说,不会增加轿车厂商类,厂商的公共办法就能得到复用。

首要,咱们界说一个动态署理类,需求完结InvocationHandler接口,然后在invoke()中增加相应的逻辑:

public classDynamicProxyWheelimplementsInvocationHandler {
privateObjectwheel; //署理的方针  
publicDynamicProxyWheel(Object wheel){  
this.wheel= wheel;  
}  
@Override  
publicObjectinvoke(Object proxy,Method method,Object[] args)throwsThrowable {  
before();  
method.invoke(wheel,args);  
after();  
return null;  
}  
private voidafter() {  
Log.i("proxyDemo","悉数拼装结束,预备交付");  
}  
private voidbefore() {  
Log.i("proxyDemo","先拼装好其他部件及体系");  
}  
}

接下来,咱们运用这个动态署理轮胎来出产各种轮胎了:

public classDynamicProxyWheelimplementsInvocationHandler {
privateObjectwheel; //署理的方针  
publicDynamicProxyWheel(Object wheel){  
this.wheel= wheel;  
}  
@Override  
publicObjectinvoke(Object proxy,Method method,Object[] args)throwsThrowable {  
before();  
method.invoke(wheel,args);  
after();  
return null;  
}  
private voidafter() {  
Log.i("proxyDemo","悉数拼装结束,预备交付");  
}  
private voidbefore() {  
Log.i("proxyDemo","先拼装好其他部件及体系");  
}  
}

Retrofit源码精析
可见,这儿少了BenZ和Tank这些厂商(署理)类。这便是动态署理的运用,而Retrofit便是经过动态署理的办法创立各种网络接口的署理。

Builder形式

Retrofit retrofit =newRetrofit.Builder()
.baseUrl("https://api.github.com") //装备URL的基地址  
.addConverterFactory(GsonConverterFactory.*create*())//装备Gson转化器  
.build();

在声明Retrofit方针的时分,咱们可以看到这儿应用了一个制作者(构建者)形式,制作者形式的特点是可以讲一个杂乱方针的构成和表明别离开来。这儿,咱们首要重视build()办法的完结:

publicRetrofitbuild() {
if(baseUrl==null) {  
throw newIllegalStateException("Base URL required.");  
}  
//设置Call的工厂类,假设没有设置,则为OkHttpClient方针  
okhttp3.Call.Factory callFactory =this.callFactory;  
if(callFactory ==null) {  
callFactory =newOkHttpClient();  
}  
//履行回调办法的方针,Android里是在主线程履行回调  
Executor callbackExecutor =this.callbackExecutor;  
if(callbackExecutor ==null) {  
callbackExecutor =platform.defaultCallbackExecutor();  
}  
//网络恳求适配器工厂调集  
// Make a defensive copy of the adapters and add the default Call adapter.  
List<CallAdapter.Factory> callAdapterFactories =newArrayList<>(this.callAdapterFactories);  
callAdapterFactories.addAll(platform.defaultCallAdapterFactories(callbackExecutor));  
//数据转化器工厂类调集,用于解析网络呼应  
// Make a defensive copy of the converters.  
List<Converter.Factory> converterFactories =  
newArrayList<>(  
1+this.converterFactories.size() +platform.defaultConverterFactoriesSize());  
// Add the built-in converter factory first. This prevents overriding its behavior but also  
// ensures correct behavior when using converters that consume all types.  
converterFactories.add(newBuiltInConverters());  
converterFactories.addAll(this.converterFactories);  
converterFactories.addAll(platform.defaultConverterFactories());  
return newRetrofit(  
callFactory,  
baseUrl,  
*unmodifiableList*(converterFactories),  
*unmodifiableList*(callAdapterFactories),  
callbackExecutor,  
validateEagerly);  
}

假设这时分是一头雾水,很正常,咱们先测验去了解代码,到终究,咱们都会看明白的。 在Build()中,初始化了回调Call的工厂类,网络恳求适配器工厂调集,数据转化器工厂调集。可见其间Call的工厂类默许完结为OkHttpClient。默许的CallAdapter.Factory为ExecutorCallAdapterFactory方针。CallAdapter.Factory首要适配接口的回来类型,如咱们上述例子的接口:

public interfaceNetService {
@GET("users/{user}/repos")  
Call<List<Repo>>getRepos(@Path("user") String user);  
}

回来为Call类型,而Call类型则是由ExecutorCallAdapterFactory适配的,假设在创立Retrofit方针的时分指定装备RxJavaCallAdapterFactory:

Retrofit retrofit =newRetrofit.Builder()
.baseUrl("https://api.github.com")  
.addCallAdapterFactory(RxJavaCallAdapterFactory.create())  
.build();

则接口getRepos的回来类型可为RxJava的Observable。

Build()中还初始化了数据转化器工厂类调集,转化器工厂首要担任网络呼应的解析,比方咱们之前代码中是:

Retrofit retrofit =newRetrofit.Builder()
.baseUrl("https://api.github.com")   
.addConverterFactory(GsonConverterFactory.*create*())  
.build();

这儿设置了GsonConverterFactory,咱们就可以运用Gson解析网络成果,当然还有其他的工厂,比方PhotoConverterFactory,可以运用PhotoBuf解析网络成果。

build()中值得留意的一行代码是:

Retrofit源码精析

Retrofit源码精析
这儿限定了默许的网络回调器,经过绑定主线程Looper的Handler强制将网络回调切换到主线程中履行。相比OkHttp3,Retrofit在运用时一个很方便当地便是在execute()或许enqueue()发起恳求后的回来成果时,不需求再切换线程,因为此刻,它现已在安卓的UI主线程傍边了。

Retrofit源码精析
这儿咱们可以总结下这几个成员变量:

serviceMethodCache:这个map的第一个泛型参数Method即是咱们的恳求办法。S erviceMethod首要代表网络恳求接口中办法进行注解之后咱们经过解析解析后拿到的方针,与注解中的post、get等办法成对出现,一一对应。serviceMethodCache看姓名就知道是缓存,在这儿首要是做网络恳求相关装备的缓存(之前2.3版本的时分是个LinkedHashMap)。

call Factory:恳求网络的OKHttp的工厂,用于“出产”OKHttp的OKHttpClient;

baseUrl:网络恳求的url的基地址,与接口参数拼接起来便是个完整的URL;

converterFactories:数据转化器工厂调集,用于出产咱们需求的数据转化器(数据转化器:对咱们做了网络恳求后得到的response进行转化成咱们设定的Java方针);

callAdapterFactories:网络恳求适配器工厂调集,用于放置咱们的网络恳求适配器工厂(网络恳求适配器:把咱们的call方针转化成其他类型);

callbackExecutor:用于履行回调,Android类中默许的网络回调履行器为Main ThreadExecutor,经过绑定主线程Looper的Handler将网络回调推送到主线程履行。(Retrofit傍边的网络恳求,终究都是经过线程池将咱们的handler来进行调配,可以处理咱们的主线程和子线程等线程切换)毫无意外,咱们处理异步的网络恳求就需求用到它;

validateEagerly:一个符号位,表明是否需求当即解析咱们接口的办法。

咱们持续看Builder(),在这儿Builder是Retrofit的静态内部类:

Retrofit源码精析
同样也有几个成员变量,有两个新参数要了解下:

Platform:表明Retrofit的适配渠道(Android,Java8等);

baseUrl:网络恳求的URL地址(留意这儿是HttpUrl,不是String);

converterFactories,callAdapterFactories,callbackExecutor,validateEagerly作用同上。

这儿的结构办法中回来的是Platform.get(),即适配渠道:

Retrofit源码精析

Retrofit源码精析

baseUrl()

Retrofit retrofit =newRetrofit.Builder()
.baseUrl("https://api.github.com")   
.addConverterFactory(GsonConverterFactory.*create*())  
.build();

在原例子中,第二行就指定baseUrl(),其办法内部首要作业便是对传入的String进行判空和URL转化:

Retrofit源码精析
留意这儿return的是转化好后的HttpUrl类型。

Retrofit源码精析

Retrofit源码精析
这儿的baseUrl()将原String拆分成多个字符碎片,然后检测终究一个字符是否是以“/”结束,假设不是则抛出反常:baseUrl不是以“/”结束。假设是的话才return。

addConverterFactory

addConverterFactory()操作比较简略,增加工厂调集:

Retrofit源码精析
那么要点便是里面的参数了:

Retrofit源码精析

Retrofit源码精析
可见,终究传的仍是Gson转化器工厂方针。

addCallAdapterFactory

Retrofit retrofit =newRetrofit.Builder()
.baseUrl("https://api.github.com")  
.addConverterFactory(GsonConverterFactory.*create*())  
.addCallAdapterFactory(RxJavaCallAdapterFactory.*create*())  
.build();

网络恳求适配器工厂,所做操作与addConverterFactory()相同,也都是相同的增加操作。

Retrofit源码精析
咱们看RxJavaCallAdapterFactory.create()的完结:

Retrofit源码精析

Retrofit源码精析
这个Scheduler便是RxJava中的调度器。也便是说这儿的.create()回来了含有Scheduler调度器方针的RxJavaCallAdapterFactory,然后增加到callAdapterFactories调集中。

方针构成

这时分再回来咱们开端的build():

Retrofit源码精析
相信到这儿,你现已不再是一头雾水了。一句话归纳这段代码的含义:将retrofit类中的一切成员变量装备结束,完结整个Retrofit方针的构建。

网络恳求

在构建好Retrofit方针后,咱们就要对其进行网络恳求了:

Retrofit源码精析
在这儿,create()用Retrofit方针回来一个NetService的完结,咱们调查下其内部完结:

Retrofit源码精析

Retrofit源码精析
validateServiceInterface()办法姓名直译便是否是有用服务接口,办法内部都是对其是否合法接口的一个判别,validateEagerly一个符号位,表明是否需求当即解析咱们接口的办法。假设是,就当即解析。这儿咱们要点看platform.isDefaultMethod()

Retrofit源码精析
判别有没有Java8的TYPES,且是默许办法。即判别是不是Java8的默许办法。

Retrofit源码精析
这个办法即判别是否是静态办法。

Java接口默许不许有默许完结,可是Java8开端可以给接口的一些办法写默许完结了;Java接口不允许写静态办法,但Java8开端允许接口里写静态办法了。然而Retrofit是不支持的这些的,即Retrofit不接纳这两种办法为service接口里的办法。

所以这儿判别便是要求不是JAVA8的默许办法和静态办法。这时分才到要点的办法来:

Retrofit源码精析
也便是说validateServiceInterface()做了一系列接口的合规性验证后,终究履行loadServiceMethod()。

在进这个办法之前,咱们先跳回原外界办法:

Retrofit源码精析
下面的代码可以看出来,是一个动态署理。咱们调查其首要逻辑,第一个判别,办法方针是否是Object(方针),假设是则直接调用不署理。接着来到return后的判别办法:

假设platform.isDefaultMethod(method),则回来platform.invokeDefaultMethod(method, service, proxy, args),假设不是,则loadServiceMethod(method).invoke(args)。

为了便于了解,上面的三元判别办法等价于:

if(platform.isDefaultMethod(method)){
platform.invokeDefaultMethod(method,service,proxy,args)  
}else{  
loadServiceMethod(method).invoke(args);  
}

仍是判别是否是默许办法,假设不是,才履行loadServiceMethod(method)。结合上面代码,可看出不管validateServiceInterface(),终究都会履行loadServiceMethod(),可见loadServiceMethod()才是要害中的要害。

loadServiceMethod()

Retrofit源码精析
这儿的synchronized线程同步锁,保证咱们的线程安全。

serviceMethod,在这儿对应的是接口办法(的封装)。serviceMethodCache在这儿是网络恳求相关装备的缓存,实质是一个Map,在这儿这个Map的key是method,假设能将对应method的value即serviceMethod取出,且不为空则return出去。假设为空,中心代码又变成了:

Retrofit源码精析
在这儿,又去测验获取serviceMethodCache中的serviceMethod。假设没有得到,即为空的情况下履行ServiceMethod.parseAnnotations():

Retrofit源码精析
先看①:

Retrofit源码精析
可以看到这个制作者形式创立了一个完整的method方针(包含了网络恳求的一切参数method,baseUrl,httpMethod,headers,contentType,hasBody,isFormEncoded,isMultipart,isKotlinSuspendFunction等,这儿不细讲了。)

再看②:

Retrofit源码精析

Retrofit源码精析
代码有点多…精简下:

static <ResponseT, ReturnT> HttpServiceMethod<ResponseT, ReturnT> parseAnnotations(
Retrofit retrofit, Method method, RequestFactory requestFactory) {
boolean isKotlinSuspendFunction = requestFactory.isKotlinSuspendFunction;//是否是Kotlin suspend办法
...
Annotation[] annotations = method.getAnnotations();//获取method的注解信息
...
if (!isKotlinSuspendFunction) {
return new CallAdapted<>(requestFactory, callFactory, responseConverter, callAdapter);
} else if (continuationWantsResponse) {
//noinspection unchecked Kotlin compiler guarantees ReturnT to be Object.
return (HttpServiceMethod<ResponseT, ReturnT>)
new SuspendForResponse<>(
requestFactory,
callFactory,
responseConverter,
(CallAdapter<ResponseT, Call<ResponseT>>) callAdapter);
} else {
//noinspection unchecked Kotlin compiler guarantees ReturnT to be Object.
return (HttpServiceMethod<ResponseT, ReturnT>)
new SuspendForBody<>(
requestFactory,
callFactory,
responseConverter,
(CallAdapter<ResponseT, Call<ResponseT>>) callAdapter,
continuationBodyNullable);
}
}

这个类中有几个参数要留意一下:

Retrofit源码精析

Retrofit源码精析
callFactory是网络恳求工厂,用于出产咱们的网络恳求Call,即OKHttp的call。代表着实践的网络恳求。

CallAdapte r表明的是网络恳求适配器,首要的把咱们的Call恳求适配不同的渠道,比方RxJava的渠道。

responseConverter表明的是数据转化器,其实便是reponse内容转化器,作用把服务器回来的Json数据转化成咱们的JavaBean方针。

Retrofit源码精析
这儿的httpMethod首要表明网络恳求的HTTP办法,比方GET,POST等等。

Retrofit源码精析
annotations即网络恳求办法中的注解,即原咱们的代码接口中的@GET等:

Retrofit源码精析

Retrofit源码精析
parameterTypes即获取咱们网络恳求接口办法里的类型。 咱们回来看其初始化的当地:

Retrofit源码精析

Retrofit源码精析

Retrofit源码精析

Retrofit源码精析
看到这儿,遍历工厂调集,然后经过get()来获得咱们需求的CallAdapter。假设没有适宜的,就抛出反常。拿到CallAdapter之后,拿到其responseType(回来的接口类型),这个时分咱们就依据咱们网络恳求办法的回来值、注解类型,从咱们的retrofit方针中获取这个网络数据适配器回来的数据类型。

Retrofit源码精析
在这儿,咱们经过createResponseConverter获取到数据转化器类型。看下这个办法的完结:

Retrofit源码精析
这儿再经过获取到的注解annotation和之前获取到的responseType再从retrofit中获取:

Retrofit源码精析

public <T> Converter<ResponseBody, T> nextResponseBodyConverter(
    @Nullable Converter.Factory skipPast, Type type, Annotation[] annotations) {
  Objects.requireNonNull(type, "type == null");
  Objects.requireNonNull(annotations, "annotations == null");
  int start = converterFactories.indexOf(skipPast) + 1;
  for (int i = start, count = converterFactories.size(); i < count; i++) {
    Converter<ResponseBody, ?> converter =
        converterFactories.get(i).responseBodyConverter(type, annotations, this);
    if (converter != null) {
      //noinspection unchecked
      return (Converter<ResponseBody, T>) converter;
    }
  }
  StringBuilder builder =
      new StringBuilder("Could not locate ResponseBody converter for ")
          .append(type)
          .append(".\n");
  if (skipPast != null) {
    builder.append("  Skipped:");
    for (int i = 0; i < start; i++) {
      builder.append("\n   * ").append(converterFactories.get(i).getClass().getName());
    }
    builder.append('\n');
  }
  builder.append("  Tried:");
  for (int i = start, count = converterFactories.size(); i < count; i++) {
    builder.append("\n   * ").append(converterFactories.get(i).getClass().getName());
  }
  throw new IllegalArgumentException(builder.toString());
}

源码逻辑流程很像之前的CallAdapter,这儿也是遍历converterFactories并从中获取适宜的数据转化器工厂,然后再经过responseBodyConverter()获取到相应的数据转化器。(默许是Json转化器,所以这儿一般获取到的是JsonResponseConverter,了解即可)这样就完结了整个数据转化器的初始化作业。

Retrofit源码精析
从接下来的代码中可以看出,if (!isKotlinSuspendFunction)时,即在Java下开发的非协程挂起函数,直接回来其子类CallAdapted<>方针。

Retrofit源码精析
这儿先暂停,咱们先看其invoke()(HttpServiceMethod extends ServiceMethod,而ServiceMethod中有笼统办法invoke()):

Retrofit源码精析
这个adapt是笼统办法,那详细的完结呢?就在上面CallAdapted中(extendsHttpServiceMethod,要复写其笼统办法adapt()),其中心代码就一行:

Retrofit源码精析
在说adapt()之前先说说OkHttpCall:

OkHttpCall

这个OkHttpCall其实便是对OkHttp中的Call的一个封装。

Retrofit源码精析
同时其结构办法也把callFactory、responseConverter等参数传入。

Retrofit源码精析
其自身也封装了异步、履行等办法,所以retrofit的网络恳求究竟仍是调用的OKHttp库。

adapt

Retrofit源码精析

Retrofit源码精析
咱们上面说到,把创立好的OkHttpCall方针传进了callAdapter的adapt()之中,并回来。

Retrofit源码精析
CallAdapter是个接口,本身没有办法完结逻辑。因为这儿是动态署理,因而咱们要到各完结类中去寻找此办法详细完结,例如RxJavaCallAdapter等:

Retrofit源码精析
其首要作用便是把咱们的一个一个的Retrofit傍边的Call转化成其他渠道也可以运用的类型。比方在RxJavaCallAdapter中就转化成了Observable,详细转化办法这儿就不细说了。

总结下,先回到咱们的网络恳求代码:

Retrofit源码精析
这儿的NetService是个接口,接口必定不能直接调用办法,所以是在create()中经过动态署理Proxy.newProxyInstance去进行拦截,然后调用其InvocationHandler中的invoke()来进行实践的操作,然后经过回来的OkHttpCall方针来进行实践的网络恳求。

所以这个netService实践上便是经过动态署理返还过来的OkHttpCall方针。而OkHttpCall方针又是对OkHttp的封装,所以这儿的.getRepos(“octocat)其实便是经过咱们的OkHttp库去恳求咱们网络然后实施同步和异步的办法。

Retrofit的恳求,OKHttp的创立

Retrofit的恳求其实也分为两种:

1、同步:OkHttpCall.execute();

2、异步:OkHttpCall.enqueue();

(这儿的OkHttpCall是指的create()里回来的OkHttpCall方针)

这儿咱们先重视咱们代码中的异步办法:

Retrofit源码精析
可见,这个call是个接口,其所对应的完结类是OkHttpCall。

Retrofit源码精析
在这儿获取call的办法要重视这个办法:

Retrofit源码精析
可以看到,call经过callFactory创立,在原OKHTTP代码中,假设要创立一个call,则代码是这样的:


okHttpClient.newCall(request).enqueue(new Callback());

newCall()中参数是一个OkHttp里的Request方针,Request方针在Retrofit中经过requestFactory.create()创立,创立好后传给callFactory的newCall()并生成okhttp3.call方针。callFactory方针的创立在HttpServiceMethod的parseAnnotations()办法中,上面现已阐明,这儿不再赘述。

Retrofit源码精析
其对应回调也在OkHttpCall中,这时不知道为什么,感觉有所遗失,咱们找到HttpServiceMethod的parseAnnotations()中的callFactory;

Retrofit源码精析

Retrofit源码精析
原来很早之前,在build()里就阐明晰Retrofit用来创立OkHttp3的Call的工厂便是OkHttp3的OkHttpClient()。同理,execute()的创立也是类似,这儿就不赘述了。此流程一走下来,OkHttp方针创立结束。

数据解析与回调

Retrofit源码精析
在call的异步办法里,在得到初始的rawResponse后,有一个parseResponse()的操作:

Response<T> parseResponse(okhttp3.Response rawResponse) throws IOException {
  ResponseBody rawBody = rawResponse.body();
  // Remove the body's source (the only stateful object) so we can pass the response along.
  rawResponse =
      rawResponse
          .newBuilder()
          .body(new NoContentResponseBody(rawBody.contentType(), rawBody.contentLength()))
          .build();
  int code = rawResponse.code();
  if (code < 200 || code >= 300) {
    try {
      // Buffer the entire body to avoid future I/O.
      ResponseBody bufferedBody = Utils.buffer(rawBody);
      return Response.error(bufferedBody, rawResponse);
    } finally {
      rawBody.close();
    }
  }
  if (code == 204 || code == 205) {
    rawBody.close();
    return Response.success(null, rawResponse);
  }
  ExceptionCatchingResponseBody catchingBody = new ExceptionCatchingResponseBody(rawBody);
  try {
    T body = responseConverter.convert(catchingBody);
    return Response.success(body, rawResponse);
  } catch (RuntimeException e) {
    // If the underlying source threw an exception, propagate that rather than indicating it was
    // a runtime exception.
    catchingBody.throwIfCaught();
    throw e;
  }
}

不难看出,在这儿,retorfit将OkHttp回来的数据进行解析,然后将回来数据转化后再return,要点在这儿:

Retrofit源码精析
这个responseConverter转化器的功用,便是将OKHttp回来的不易看懂的数据转化为咱们自界说的JavaBean,在之前HttpServiceMethod.parseAnnotations()中:

Retrofit源码精析
前文有讲述,终究调用的当地是

Retrofit源码精析
遍历converterFactories并从中获取适宜的数据转化器工厂,然后再经过responseBodyConverter()获取到相应的数据转化器。(默许是Json转化器,所以这儿一般获取到的是JsonResponseConverter,了解即可)咱们可以看出responseConverter来自于converterFactories,而在Retrofit的build()中:

Retrofit源码精析
而这个this.converterFactories赋值的当地在:

Retrofit源码精析
即咱们写的代码中的:

Retrofit源码精析
也便是说这个最早初始化的Gson转化器终究被OkHttpCall的parseResponse()中的responseConverter.convert(catchingBody);调用。

Retrofit源码精析
这儿解析结束后,会履行onResponse回调,将OkHttpCall方针和解析数据后的response方针回调出去,对应的咱们的代码中的:

Retrofit源码精析

规划形式

经过上述的源码流程整理,不难发现Retrofit其实实质上便是一个网络恳求结构的封装。实践上的网络恳求等功用完结都是交给了OkHttp去完结。在这些代码封装之中,融合了太多的规划形式在里面。

制作者形式

Retrofit源码精析
这儿很明显有个构建者形式,构建者形式将一个杂乱方针的结构与它的表明别离,使得制作进程可以创立不同的表明 其优点很明显,这儿构建者形式加上链式调用为Retrofit的参数装备增加不少灵活度,进一步增强代码可读性。

外观形式 门面形式

门面形式要求一个子体系的外部与其内部通讯必须经过一个共同的方针进行。Retrofit给咱们暴露的办法和类不多。中心类便是Retrofit,咱们只管装备Retrofit,然后获取接口方针恳求数据,设置回调,其他的都是Retrofit结构内部的事情了。这儿Retrofit的门面是Retrofit.create() 。这样的代码规划能降低体系耦合度,除了Retrofit,平时开发常用的开源结构Glide也有一个门面,比方Glide.with(xxx)…。

动态署理

动态署理指的是程序运转的时分创立署理类的办法,署理形式中最重要的便是区别人物: 1、方针接口;2、方针方针;3、署理方针。

Retrofit中则是经过Proxy.newProxyInstance去调用其InvocationHandler中的invoke()来完结动态署理,详情上面现已阐明,这儿不再赘述。

Retrofit源码精析

装修形式

装修形式是在不改动原类文件和运用继承的情况下,动态的扩展一个方针的功用。Retrofit中用装修形式的便是ExecutorCallbackCall了。

Retrofit源码精析

简略说下,enqueue()办法是异步的,当你调用OkHttpCall的enqueue办法,回调的callback在子线程中,假设需求在主线程接受回调,那就要经过Handler转化到主线程上去。ExecutorCallbackCall便是用来干这个事。当然以上是retrofit默许运用的切换线程办法。假设咱们指定用rxjava,那就不会用到这个ExecutorCallbackCall而是RxJava的Call了。

也许你会感觉,装修形式与静态署理形式很像。但这俩者区别也不小:装修形式里,装修后的方针仍是“我”,只不过装修完后“我”的功用更加强壮;署理形式里方针现已不是“我”了,只不过署理形式可以联络到我罢了。

战略形式

战略形式界说了一组算法,将每个算法都封装起来,而且使它们之间可以交换。在CallAdapter中可以增加多个CallAdapter.Factory方针,相当于咱们封装了多个不同的适配算法CallAdapter.adapt()。上文现已阐明,其方针的生成初始化和调用都在HttpServerMethod.parseAnnotations()中:

static <ResponseT, ReturnT> HttpServiceMethod<ResponseT, ReturnT> parseAnnotations(
      Retrofit retrofit, Method method, RequestFactory requestFactory) {
      ......
    CallAdapter<ResponseT, ReturnT> callAdapter =
        createCallAdapter(retrofit, method, adapterType, annotations);
    Type responseType = callAdapter.responseType();
    ......
    }
    ......
  }
  private static <ResponseT, ReturnT> CallAdapter<ResponseT, ReturnT> createCallAdapter(
      Retrofit retrofit, Method method, Type returnType, Annotation[] annotations) {
    try {
      //noinspection unchecked
      return (CallAdapter<ResponseT, ReturnT>) retrofit.callAdapter(returnType, annotations);
    } catch (RuntimeException e) { 
      .......
    }
  }

然后办法履行到Retrofit方针的callAdapter() -> nextCallAdapter()。

Retrofit源码精析

Retrofit源码精析
在的nextCallAdapter()中,依据回来值retrunType类型遍历调用CallAdapter.Factory的get()办法:

Retrofit源码精析
假设回来的CallAdapter方针不为null则直接回来该方针,此逻辑即印证了CallAdapter.Factory的get()应该是依据retrunType确定是否回来CallAdapter方针(是否挑选该种战略)。

适配器形式

适配器形式将一个类的接口变换为客户端等待的另一种接口,从而使原本因接口不匹配而无法在一起作业的两个类可以在一起作业。Retrofit代码中将很多的规划形式融合在一起,除了战略形式,CallAdapter中还有此形式,

Retrofit源码精析
这段注释似乎便是在阐明,将呼应类型为{@code R}的{@link Call}修改为{@code T}类型。Retrofit中,CallAdapter就选用了适配器形式为创立拜访Call接口提供服务。默许情况下运用默许的ExecutorCallAdapterFactory将okhttp3.call改变成为retroift中的call,假设设定RxJava,则将okhttp3.call转化为Observable。上述源码有剖析,此处不赘述。