前言 上两篇文章:
Retrofit与Okhttp是Android开发中最最热门的网络请求库,它们都来自square公司,Okhttp在前面的两篇文章中已经通过源码从请求流程和拦截器两个角度分析过,本文的主角是Retrofit,经过这几天的研究,我发现Retrofit只是一个对Okhttp网络请求框架的巧妙包装,它通过注解去定义一个HTTP请求,然后在底层通过Okhttp发起网络请求,就是这样的一个简单的过程,其间运用了很多的设计模式:外观模式、动态代理模式、适配器模式、装饰者模式等,其最核心的是动态代理模式,所以在此之前大家对动态代理要有一个了解:
静态和动态代理模式
其他的设计模式我会在讲解的过程中简单介绍,除了使用了大量的设计模式,Retrofit还应用了面向接口编程的思想,使得整个系统解耦彻底,本文会通过一个简单的Retrofit使用示例,然后引出Retrofit的核心类,面向接口思想、构建过程、动态代理和网络请求过程,通过这几部分来解剖Retrofit。
Retrofit的项目地址:Retrofit
本文源码基于Retrofit2.4
一、Retrofit的简单使用 首先来回忆一下Retrofit的使用,我这里使用的是Github 平台的开放api,这个api根据用户名获取一个用户信息,首先在你的AndroidManifest.xml中声明网络权限,然后:
1、创建一个Api接口
1 2 3 4 5 6 public interface GithubService { @GET ("users/{user}" ) Call<ResponseBody> getUserInfo (@Path("user" ) String user) ; }
我用Retrofit的注解声明了一个GET请求的方法,Call是Retrofit中的Call,而不是Okhttp中的Call,而ResponseBody是Okhttp的ResponseBody。
2、创建Retrofit实例
1 2 3 Retrofit Retrofit = new Retrofit.Builder() .baseUrl("https://api.github.com/" ) .build();
使用Builder模式构建Retrofit实例,传入baseUrl,我们平常开发一般会添加Rxjava2CallAdapterFactory和GsonConverterFactory,但这里我没有使用addCallAdapterFactory(Factory)来添加CallAdapterFactory,也没有使用addConverterFactory(Factory)来添加ConverterFactory,都使用默认的CallAdapter和Converter,默认的CallAdapter返回的就是Retrofit中的Call类型,默认的Converter会把网络请求返回数据转化为Okhttp中的ResponseBody,这也就是我上面定义接口时,Cal的T是ResponseBody的原因。
3、创建Api接口实例
1 GithubService service = Retrofit.create(GithubService.class ) ;
通过Retrofit实例的create方法创建Api接口实例GithubService。
4、调用Api接口的方法,生成Call
1 Call<ResponseBody> call = service.getUserInfo("rain9155" );
调用Api接口的方法,会返回一个Call实例。
5、通过Call发起同步或异步请求,然后获取返回结果Response
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 Response<ResponseBody> response = call.execute(); 或 call.enqueue(new Callback<ResponseBody>() { @Override public void onResponse (Call<ResponseBody> call, Response<ResponseBody> response) { ResponseBody body = response.body(); try { Log.d(TAG, "请求结果:" + body.string()); } catch (IOException e) { e.printStackTrace(); } } @Override public void onFailure (Call<ResponseBody> call, Throwable t) { } });
通过Call的execute或enqueue方法发起网络请求,当网络请求结果返回时,就可以通过Response的body方法获取,这里因为使用默认的Converter,所以获取到的body的是Okhttp的ResponseBody,log的输出结果是JSON数据 。
这就是Retrofit发起网络请求的五步曲,如果除去第一步,和Okhttp的使用还是非常的相似的,因为Retrofit和Okhttp的类名有很多的重复,下面如果涉及Okhttp的相关类,我会特别说明,否则默认都是属于Retrofit的。
二、Retrofit的相关类介绍 先简单的介绍一下重要的类,会对后面的阅读有帮助,当我们把Retrofir的源码clone下来,发现里面有4个主要的模块,分别是:
retrofit-adapter
retrofit-converters
retrofit-mock
retrofit
其中retrofit-mock是测试时用的,不关我们的事,和我们开发相关的是retrofit-adapter、retrofit-converters和retrofit模块,当我们没有使用外置的CallAdapter和Converters时,我们只需要依赖retrofit模块,retrofit模块中有3个非常重要的接口,分别是:
Call : 网络请求执行器,用于执行同步或异步的网络请求,内部最终通过Okhttp的Call发起网络请求
CallAdapter :网络请求适配器,它用于把默认的网络请求执行器的调用形式,适配成在不同平台下的网络请求执行器的调用形式,例如Retrofit默认通过Call,内部使用ExecutorCallbackCall通过handler来执行网络请求后的线程切换,通过添加RxjavaCallAdapter后,RxjavaCallAdapter把默认的网络请求执行器适配成Observerable或Flowable,这样我可以使用Rxjava的链式调用方式来执行网络请求后的线程切换。
Converter :数据转化器,两个方向的转化,把Api接口方法的参数注解的值转化为网络请求执行器需要的数据类型,和把网络返回的数据转化为我们需要的数据类型。
还有一个Callback接口,用于回调网络请求成功或失败,很简单,就不介绍了,其中CallAdapter和Converter内部都有一个Factory类,它都是通过工厂模式 创建,工厂模式就是将复杂对象的实例化任务交给一个类去实现,使得使用者不用知道具体参数就可以实例化出所需要的对象 ,在Retrofit中,想要获得CallAdapter或Converter的实例都需要通过Factory来获取。下面分别简单的介绍一下Call、CallAdapter和Converter接口的作用和在Retrofit下的默认实现。
1、Call 网络请求执行器,用于执行同步或异步的网络请求,Call接口如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 public interface Call <T > extends Cloneable { Response<T> execute () throws IOException ; void enqueue (Callback<T> callback) ; boolean isExecuted () ; void cancel () ; boolean isCanceled () ; Call<T> clone () ; Request request () ; }
Retrofit的Call和Okhttp的Call接口定义的方法差不多,只是多了一个clone方法,在Retrofit中,Call的默认实现类是OkHttpCall,如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 final class OkHttpCall <T > implements Call <T > { private final ServiceMethod<T, ?> serviceMethod; private final @Nullable Object[] args; private @Nullable okhttp3.Call rawCall; private @Nullable Throwable creationFailure; private boolean executed; private volatile boolean canceled; Override public Response<T> execute () throws IOException { okhttp3.Call call; call = rawCall; return parseResponse(call.execute()); } @Override public void enqueue (final Callback<T> callback) { okhttp3.Call call; call = rawCall; call.enqueue(new okhttp3.Callback() { @Override public void onResponse (okhttp3.Call call, okhttp3.Response rawResponse) { callback.onResponse(OkHttpCall.this , response); } @Override public void onFailure (okhttp3.Call call, IOException e) { callFailure(e); } }); } }
一个OkHttpCall实例就代表着一次网络请求,OkHttpCall里面大部分方法的逻辑都是转发给Okhttp的Call方法。
在本文,不管来自Okhttp的Call,还是来自Retrofit的Call,都可以理解为网络请求执行器。
2、CallAdapter 网络请求适配器,用于把默认的网络请求执行器的调用形式,适配成在不同平台下的网络请求执行器的调用形式,CallAdapter接口如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 public interface CallAdapter <R , T > { Type responseType () ; T adapt (Call<R> call) ; abstract class Factory { public abstract @Nullable CallAdapter<?, ?> get(Type returnType, Annotation[] annotations, Retrofit Retrofit); protected static Type getParameterUpperBound (int index, ParameterizedType type) { return Utils.getParameterUpperBound(index, type); } protected static Class<?> getRawType(Type type) { return Utils.getRawType(type); } } }
CallAdapter接口很简单,只有两个方法responseType和adapt方法,和一个Factory类,其中Factory类的get方法可以获取一个CallAdapter示例,CallAdapter的responseType方法就是获得Call中的T类型,这个Call就是我们在定义Api接口方法时方法的返回参数,CallAdapter的adapt方法 用于把传入的Call适配成另外一个我们所期待的’Call’,这里使用到了适配器模式 ,适配器模式就是在两个因接口不兼容的类之间加一个适配器,将一个类的接口变成客户端所期待的另一种接口,从而使得它们工作在一起 ,至于怎么适配就需要看适配器中得adapt方法的实现,接下来我们看adapt方法在Retrofit中的默认实现。(在Android Platform下的默认实现,Platform的概念在构建过程中会讲到)
在Retrofit中,CallAdapter的默认实现是一个匿名类,可以通过CallAdapter的Factory获得,CallAdapter的Factory的默认实现是ExecutorCallAdapterFactory ,如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 final class ExecutorCallAdapterFactory extends CallAdapter .Factory { final Executor callbackExecutor; ExecutorCallAdapterFactory(Executor callbackExecutor) { this .callbackExecutor = callbackExecutor; } @Override public CallAdapter<?, ?> get(Type returnType, Annotation[] annotations, Retrofit Retrofit) { if (getRawType(returnType) != Call.class ) { return null ; } final Type responseType = Utils.getCallResponseType(returnType); return new CallAdapter<Object, Call<?>>() { @Override public Type responseType () { return responseType; } @Override public Call<Object> adapt (Call<Object> call) { return new ExecutorCallbackCall<>(callbackExecutor, call); } }; } static final class ExecutorCallbackCall <T > implements Call <T > { } }
在ExecutorCallAdapterFactory的get方法中,new了一个CallAdapter返回,在CallAdapter的adapt方法实现中,new了一个ExecutorCallbackCall返回,并把入参call和callbackExecutor传进了ExecutorCallbackCall的构造中,ExecutorCallbackCall就是一个实现了Call接口的类,还是一个Call,它就是Retrofit的默认网络请求执行器,可以看到Retrofit的默认的网络请求执行器适配,即adapt方法的默认实现就是用ExecutorCallbackCall包装传进来的Call,并返回ExecutorCallbackCall,这个传进来的Call就是Call的默认实现OkHttpCall ,待会在Retrofit的构建过程中还会讲到。
既然CallAdapter能把默认的网络请求执行器的调用形式,适配成在不同平台下的网络请求执行器的调用形式,那么它支持哪些平台呢?这个在retrofit-adapter 模块中可以找到答案,如下:
Retrofit还支持guava、java8、rxjava、scala这四个平台,它们里面都各自实现了retrofit模块暴露出去的CallAdapter接口和CallAdapter接口中的Factory接口,在CallAdapter的adapt方法中提供各自平台的适配,我们可以通过addCallAdapterFactory(Factory)来添加不同平台的CallAdapter工厂。
3、Converter 数据转化器,把我们在Api接口定义的方法注解和参数转化为网络请求执行器需要的请求类型,和把网络返回的数据转化为我们需要的数据类型,Converter接口如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 public interface Converter <F , T > { T convert (F value) throws IOException ; abstract class Factory { public @Nullable Converter<ResponseBody, ?> responseBodyConverter(Type type, Annotation[] annotations, Retrofit Retrofit) { return null ; } public @Nullable Converter<?, RequestBody> requestBodyConverter(Type type, Annotation[] parameterAnnotations, Annotation[] methodAnnotations, Retrofit Retrofit) { return null ; } public @Nullable Converter<?, String> stringConverter(Type type, Annotation[] annotations, Retrofit Retrofit) { return null ; } protected static Type getParameterUpperBound (int index, ParameterizedType type) { return Utils.getParameterUpperBound(index, type); } protected static Class<?> getRawType(Type type) { return Utils.getRawType(type); } } }
Converter接口也很简单,只有一个convert方法,和一个Factory类,因为Converter要提供两个方向的转化,所以Factory类就提供了两个方法用于获取不同方向的转化,其中responseBodyConverter方法就是获得一个把网络返回的数据转化为我们需要的数据类型的Converter实例,而requestBodyConverter方法就是获得一个把我们在Api接口定义的方法注解和参数转化为网络请求的Converter实例,那么要怎么转化呢?就要看Converter的convert方法的实现,convert方法把F类型 转化为 T类型,接下来我们看convert方法在Retrofit中的默认实现。
Converter在Retrofit的默认实现有五个,都是Converter的Factory的内部类,可通过Converter的Factory获得,Converter的Factory的默认实现是BuiltInConverters ,如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 final class BuiltInConverters extends Converter .Factory { @Override public Converter<ResponseBody, ?> responseBodyConverter(Type type, Annotation[] annotations, Retrofit Retrofit) { if (type == ResponseBody.class ) { return Utils.isAnnotationPresent(annotations, Streaming.class ) ? StreamingResponseBodyConverter .INSTANCE : BufferingResponseBodyConverter.INSTANCE; } if (type == Void.class ) { return VoidResponseBodyConverter.INSTANCE; } return null ; } @Override public Converter<?, RequestBody> requestBodyConverter(Type type, Annotation[] parameterAnnotations, Annotation[] methodAnnotations, Retrofit Retrofit) { if (RequestBody.class .isAssignableFrom (Utils .getRawType (type ))) { return RequestBodyConverter.INSTANCE; } return null ; } static final class VoidResponseBodyConverter implements Converter <ResponseBody , Void > { static final VoidResponseBodyConverter INSTANCE = new VoidResponseBodyConverter(); @Override public Void convert (ResponseBody value) { value.close(); return null ; } } static final class RequestBodyConverter implements Converter <RequestBody , RequestBody > { static final RequestBodyConverter INSTANCE = new RequestBodyConverter(); @Override public RequestBody convert (RequestBody value) { return value; } } static final class StreamingResponseBodyConverter implements Converter <ResponseBody , ResponseBody > { static final StreamingResponseBodyConverter INSTANCE = new StreamingResponseBodyConverter(); @Override public ResponseBody convert (ResponseBody value) { return value; } } static final class BufferingResponseBodyConverter implements Converter <ResponseBody , ResponseBody > { static final BufferingResponseBodyConverter INSTANCE = new BufferingResponseBodyConverter(); @Override public ResponseBody convert (ResponseBody value) throws IOException { try { return Utils.buffer(value); } finally { value.close(); } } } static final class ToStringConverter implements Converter <Object , String > { static final ToStringConverter INSTANCE = new ToStringConverter(); @Override public String convert (Object value) { return value.toString(); } } }
BuiltInConverters实现了Factory中的responseBodyConverter和requestBodyConverter方法,内部含有五个Converter默认实现类,在Factory的responseBodyConverter和requestBodyConverter方法中分别返回这几Converter实例,其中只有ToStringConverter没有使用到,我们还发现了这五个Converter的convert方法的实现除了BufferingResponseBodyConverter,大部分都是,入参是是什么,返回就是什么,所以Retrofit中Converter默认实现的convert方法大部分都没有对数据进行转化,返回原始数据,这些原始数据是String或来自Okhttp的ResponseBody、RequestBody ,例如ResponseBodyConverter的convert方法就是返回Okhttp的ResponseBody,RequestBodyConverter的convert方法就是返回Okhttp的RequestBody。
Converter除了默认的返回原始数据,它还支持哪些数据转化呢?这个在retrofit-converters模块中可以找到答案,如下:
可以看到Retrofit还支持json、xml、protobuf等多种数据类型的转化,这些子模块都各自实现了retrofit模块暴露出来的Converter接口和Converter接口中的Factory接口,在Converter的adapt方法中实现不同数据类型的转化逻辑,我们可以通过addConverterFactory(Factory)来支持不同数据类型转化的Converter工厂。
4、面向接口设计 在retrofit模块中提供了Call、Callback、CallAdapter、Converter接口 供外部模块使用,CallAdapter和Converter接口中还有相应的Factory接口,各模块之前通过接口依赖主模块Retrofit,将网络请求、网络请求适配、请求处理与返回解析完全解耦,当需要修改Retrofit中的默认实现时,只需要add一个外部模块提供的工厂,具体创建什么样的实例由工厂方法来负责,这样就能以最小的代价(不需要改动代码)换成其他模块上的实现,Retrofit本身并不参与这个过程,它只是负责提供一些主要的参数供它们进行决策,以及进行参数的处理,模块之间依赖于接口,而不依赖于具体的实现,这是一种很好的编程思路,面向接口编程。
面向接口编程:也被熟知为基于接口的设计,是一种基于组件级别的,面向对象语言的模块化编程设计实现,面向接口编程是面向对象编程的一种模块化实现形式,理论上说具有对象概念的程序设计都可以称之为面向对象编程,而面向接口编程则是从组件的级别来设计代码,将抽象与实现分离。
好了,在简单的了解了一下待会和构建过程涉及到的相关类,接下来分析Retrofit的构建过程。
三、Retrofit的创建过程 1 2 3 Retrofit Retrofit = new Retrofit.Builder() .baseUrl("https://api.github.com/" ) .build();
Retrofit是使用Builder模式 构建出一个Retrofit实例的,Builder模式的好处就是将一个复杂对象的构建和它的表示分离,在用户在不知道内部构建细节的情况下,可以更加精准的控制对象的构造过程 ,所以我们直接看Retrofit的内部类Builder就行,因为在Builder中配置的字段最终都在build时赋值给Retrofit中相应的字段,Builder只是暂时保存这些配置字段而已,下面我们分注释的3步去看Retrofit的Builder.
1、构造Builder Builder类如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 public static final class Builder { private final Platform platform; Builder(Platform platform) { this .platform = platform; } public Builder () { this (Platform.get()); } Builder(Retrofit Retrofit) { platform = Platform.get(); callFactory = Retrofit.callFactory; baseUrl = Retrofit.baseUrl; } }
new Retrofit.Builder(),我们使用了无参的构造函数来创建Builder,Builder的无参构造函数首先通过Platform.get() 获取了一个Platform实例赋值给了platform字段,前面提到过Retrofit是有Platform的概念,Retrofit支持java和Android平台,我们来看一下Platform这个类,如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 class Platform { private static final Platform PLATFORM = findPlatform(); static Platform get () { return PLATFORM; } private static Platform findPlatform () { try { Class.forName("android.os.Build" ); if (Build.VERSION.SDK_INT != 0 ) { return new Android(); } } catch (ClassNotFoundException ignored) { } try { Class.forName("java.util.Optional" ); return new Java8(); } catch (ClassNotFoundException ignored) { } return new Platform(); } Executor defaultCallbackExecutor () { return null ; } CallAdapter.Factory defaultCallAdapterFactory (@Nullable Executor callbackExecutor) { if (callbackExecutor != null ) { return new ExecutorCallAdapterFactory(callbackExecutor); } return DefaultCallAdapterFactory.INSTANCE; } boolean isDefaultMethod (Method method) { return false ; } @Nullable Object invokeDefaultMethod (Method method, Class<?> declaringClass, Object object, @Nullable Object... args) throws Throwable { throw new UnsupportedOperationException(); } @IgnoreJRERequirement static class Java8 extends Platform { } static class Android extends Platform { } }
首先Platform的get方法通过单例模式 返回了一个Platform实例,单例模式就是保证单例对象的类在同一进程中,只有一个实例存在 ,Platform实例通过findPlatform方法创建,可以看到findPlatform方法里面区分了Android、java和其他平台返回了不同的Platform实现,由于我这里是Android平台,只关注Android平台的实现,Android类如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 static class Android extends Platform { @Override public Executor defaultCallbackExecutor () { return new MainThreadExecutor(); } @Override CallAdapter.Factory defaultCallAdapterFactory (@Nullable Executor callbackExecutor) { if (callbackExecutor == null ) throw new AssertionError(); return new ExecutorCallAdapterFactory(callbackExecutor); } static class MainThreadExecutor implements Executor { private final Handler handler = new Handler(Looper.getMainLooper()); @Override public void execute (Runnable r) { handler.post(r); } } }
Android继承自Platform,重写了它其中的两个方法:defaultCallbackExecutor方法和defaultCallAdapterFactory方法,defaultCallbackExecutor方法返回了一个MainThreadExecutor,它是一个Executor ,它的execute方法的实现就是简单通过Handler 把任务Runnable切换回主线程执行,就是说,线程池会把每一个线程提交的任务都切回主线程执行,我们再来看defaultCallAdapterFactory方法,这个方法返回了我们上面介绍过的ExecutorCallAdapterFactory,并把callbackExecutor传了进去,其实这个callbackExecutor就是MainThreadExecutor ,待会在第3步构建Retrofit实例时就会讲到。
这里我们来小结一下:
new Retrofit.Builder()里面会通过Platform的get方法来获取一个Platform实例,在Android中,它会返回Android平台实例,这样就指定了Retrofit的运行平台是Android,然后就可以通过Android平台实例的defaultCallbackExecutor方法 返回一个线程切换执行器MainThreadExecutor,它用于把任务切换回主线程执行,和通过defaultCallAdapterFactory方法 返回一个网络请求适配器工厂ExecutorCallAdapterFactory,工厂中持有一个线程切换执行器实例,通过工厂就可以获取网络请求适配器实例。
有了Builder实例后,下面开始配置Builder.
2、配置Builder 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 public static final class Builder { private final Platform platform; private @Nullable okhttp3.Call.Factory callFactory; private HttpUrl baseUrl; private final List<Converter.Factory> converterFactories = new ArrayList<>(); private final List<CallAdapter.Factory> callAdapterFactories = new ArrayList<>(); private @Nullable Executor callbackExecutor; private boolean validateEagerly; public Builder baseUrl (String baseUrl) { checkNotNull(baseUrl, "baseUrl == null" ); HttpUrl httpUrl = HttpUrl.parse(baseUrl); if (httpUrl == null ) { throw new IllegalArgumentException("Illegal URL: " + baseUrl); } return baseUrl(httpUrl); } public Builder baseUrl (HttpUrl baseUrl) { checkNotNull(baseUrl, "baseUrl == null" ); List<String> pathSegments = baseUrl.pathSegments(); if (!"" .equals(pathSegments.get(pathSegments.size() - 1 ))) { throw new IllegalArgumentException("baseUrl must end in /: " + baseUrl); } this .baseUrl = baseUrl; return this ; } public Builder addConverterFactory (Converter.Factory factory) { converterFactories.add(checkNotNull(factory, "factory == null" )); return this ; } public Builder addCallAdapterFactory (CallAdapter.Factory factory) { callAdapterFactories.add(checkNotNull(factory, "factory == null" )); return this ; } public List<CallAdapter.Factory> callAdapterFactories() { return this .callAdapterFactories; } public List<Converter.Factory> converterFactories() { return this .converterFactories; } public Builder validateEagerly (boolean validateEagerly) { this .validateEagerly = validateEagerly; return this ; } }
Builder中所有的字段都贴出来了,方法只贴了几个常用的出来,我们调用Builder的相应方法,就是在为Builder的相应字段赋值,很简单,就不介绍了。
其中要注意的是:当我们添加ConverterFactory或CallAdapterFactory时,它们都是添加到各自的列表中,这说明在Retrofit中Converter和CallAdapter是可以存在多个的,为什么呢?这是因为Retrofit允许我们为Api接口里面定义的每一个方法都定义对应的Converter和CallAdapter,每当我们调用到Api接口的某个方法时,Retrofit都会遍历网络请求适配器工厂列表callAdapterFactories,把方法的返回值returnType和注解信息annotations传进每个Factory的get方法中,看某个Factory是否愿意处理这个方法,为这个方法创建对应CallAdapter实例;同理,当Retrofit解析某个Api接口方法的网络请求数据时,它同样会遍历数据转化器工厂列表converterFactories,把方法的相关信息传给Factory的responseBodyConverter或requestBodyConverter方法,看某个Factory是否愿意处理这个方法,为这个方法创建对应ResponseBodyBodyConverter或RequestBodyConverter实例,这两个过程在待会的源码分析都会体现到。由于我们平常开发都只添加了一个CallAdapter和一个Converter,所以Retrofit对Api接口定义的每一个方法的adapt和convert都是相同的处理。
配置好Builder后,接下来调用build方法创建Retrofit实例.
3、创建Retrofit实例 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 public static final class Builder { public Retrofit build () { if (baseUrl == null ) { throw new IllegalStateException("Base URL required." ); } okhttp3.Call.Factory callFactory = this .callFactory; if (callFactory == null ) { callFactory = new OkHttpClient(); } Executor callbackExecutor = this .callbackExecutor; if (callbackExecutor == null ) { callbackExecutor = platform.defaultCallbackExecutor(); } List<CallAdapter.Factory> callAdapterFactories = new ArrayList<>(this .callAdapterFactories); callAdapterFactories.add(platform.defaultCallAdapterFactory(callbackExecutor)); List<Converter.Factory> converterFactories = new ArrayList<>(1 + this .converterFactories.size()); converterFactories.add(new BuiltInConverters()); converterFactories.addAll(this .converterFactories); return new Retrofit(callFactory, baseUrl, unmodifiableList(converterFactories), unmodifiableList(callAdapterFactories), callbackExecutor, validateEagerly); } }
build方法中把没有在配置Builder阶段中赋值的字段指定了默认值,然后把网络请求Url地址baseUrl、网络请求执行器工厂callFactory、线程切换执行器callbackExecutor、网络请求适配器工厂列表callAdapterFactories、数据转化器工厂列表converterFactories、标志位validateEagerly这六件套传进了Retrofit的构造,创建一个Retrofit实例返回。
其中要注意的是,按照添加顺序,工厂列表的优先级为:用户指定的网络请适配器工厂列表 > 运行平台默认的网络请求适配器工厂;Retrofit默认的数据转化器工厂 > 用户指定的数据转化器工厂列表。在遍历这些列表时是从前往后遍历的,越靠前的越先被访问。
4、小结 经过这3步后,指定了Retrofit的运行平台,配置好了Retrofit的网络请求Url地址、网络请求执行器工厂、线程切换执行器、网络请求适配器工厂列表、数据转化器工厂列表等字段,并创建了一个Retrofit实例.
有了Retrofit实例后,就可以通过Retrofit的create方法创建一个Api接口实例,这也是整个Retrofit最核心的地方.
四、创建Api接口实例 1 GithubService service = Retrofit.create(GithubService.class ) ;
我先讲一下Retrofit的create方法的作用,Retrofit的create方法里面干了两件事,首先它会根据validateEagerly标志位是否为true,而从决定是否把Api接口里定义的所有方法的注解和参数信息提前封装到ServiceMethod中然后缓存起来,接着就通过Proxy的newProxyInstance方法为GithubService接口创建一个代理对象返回,这里就使用到了外观模式 ,外观模式就是定义一个统一接口,外部(用户)通过该统一的接口对子系统里的其他接口进行访问 ,这里的这个统一的接口就是Retrofit.create方法 ,我们只需要调用create方法,Retrofit内部就替我们把这两件事给做了,不用我们访问Retrofit的内部子系统,降低了我们使用的复杂度。
Retrofit的create方法如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 public <T> T create (final Class<T> service) { Utils.validateServiceInterface(service); if (validateEagerly) { eagerlyValidateMethods(service); } return (T) Proxy.newProxyInstance(service.getClassLoader(), new Class<?>[] { service }, new InvocationHandler() { } }); } private void eagerlyValidateMethods (Class<?> service) { Platform platform = Platform.get(); for (Method method : service.getDeclaredMethods()) { if (!platform.isDefaultMethod(method)) { loadServiceMethod(method); } } }
我们先看create方法的注释1,validateEagerly这个标志位决定是否对serviceMethod进行提前缓存,默认为false,当为true时,create方法中就会调用eagerlyValidateMethods方法,里面会遍历Api接口的所有方法,为每一个方法都调用一次loadServiceMethod方法(invoke方法中会讲到这个方法),loadServiceMethod方法中就会把方法的注解和参数信息封装到ServiceMethod中,以方法method为键,ServiceMethod为值,放入一个名叫serviceMethodCache 的Map中缓存起来,这个Map定义在Retrofit中,如下:
1 2 3 4 public final class Retrofit { private final Map<Method, ServiceMethod<?, ?>> serviceMethodCache = new ConcurrentHashMap<>(); }
可以看到这个Map是一个线程安全的HashMap,它的key = Method,value = ServiceMethod。所以可以根据需要设置validateEagerly标志位开启ServiceMethod的预加载,这样等到动态执行invoke方法时可以直接从缓存中获取ServiceMethod实例。
我们重点看create方法的注释2,通过Proxy的newProxyInstance方法为GithubService接口创建一个代理对象,这里就使用了动态代理模式 ,Proxy的newProxyInstance方法会在代码运行时 ,根据第一个参数的ClassLoader,生成一个代理Class对象,该代理Class对象实现了传入的第二个参数对应的Interface列表,在获取到代理Class对象后,根据第三个参数InvocationHandler引用通过反射创建一个代理对象实例,所以newProxyInstance最终的结果是生成一个代理对象实例,该代理对象会实现给定的接口列表,同时内部持有一个InvocationHandler引用,我们调用代理对象的方法时,这个方法处理逻辑就会委托给InvocationHandler实例的invoke方法执行 。
小结 当我们调用Retrofit的create方法后,它返回了一个代理对象实例,这个代理对象实现了create方法传进去的接口,接下来当我们调用Api接口的方法时,就是在调用代理对象的同名方法,这个方法处理逻辑就会委托给InvocationHandler实例的invoke方法执行,使用了动态代理之后的好处就是我们可以把发起网络请求的参数获取都集中到invoke方法中处理,而不需要为每一个接口定义一个实现类,这样降低了实现的难度。
接下来我们开始调用Api接口的方法,它会返回一个网络请求执行器。
五、调用Api接口实例的方法 1 Call<ResponseBody> call = service.getUserInfo("rain9155" );
根据动态代理的知识,我们知道,当我们调用Api接口实例的方法,就是在调用代理对象的方法,这个方法处理逻辑就会委托给InvocationHandler实例的invoke方法执行,也就是说,当我们在外部调用Api接口的相应方法时,这些方法都会转到invoke方法执行,例如我调用service.getUserInfo(“rain9155”)时,这个方法会转到invoke方法去执行。
所以我们直接看InvocationHandler的invoke方法逻辑:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 public <T> T create (final Class<T> service) { return (T) Proxy.newProxyInstance(service.getClassLoader(), new Class<?>[] { service }, new InvocationHandler() { private final Platform platform = Platform.get(); @Override public Object invoke (Object proxy, Method method, @Nullable Object[] args) throws Throwable { if (method.getDeclaringClass() == Object.class ) { return method.invoke(this , args); } if (platform.isDefaultMethod(method)) { return platform.invokeDefaultMethod(method, service, proxy, args); } ServiceMethod<Object, Object> serviceMethod = (ServiceMethod<Object, Object>) loadServiceMethod(method); OkHttpCall<Object> okHttpCall = new OkHttpCall<>(serviceMethod, args); return serviceMethod.adapt(okHttpCall); } }); }
invoke方法中分为注释1、2、3,下面分别讲解:
注释1、loadServiceMethod方法 1 2 ServiceMethod<Object, Object> serviceMethod = (ServiceMethod<Object, Object>) loadServiceMethod(method);
loadServiceMethod方法如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 ServiceMethod<?, ?> loadServiceMethod(Method method) { ServiceMethod<?, ?> result = serviceMethodCache.get(method); if (result != null ) return result; synchronized (serviceMethodCache) { result = serviceMethodCache.get(method); if (result == null ) { result = new ServiceMethod.Builder<>(this , method).build(); serviceMethodCache.put(method, result); } } return result; }
可以看到这里首先从serviceMethodCache根据方法method获取ServiceMethod,如果获取不到再为方法创建一个ServiceMethod,然后以方法method为键,ServiceMethod为值,放入serviceMethodCache缓存起来,并返回,我们重点来看注释1,看这个ServiceMethod是怎样根据方法的Method对象创建出来的 。
1、ServiceMethod的创建过程 1 2 result = new ServiceMethod.Builder<>(this , method) .build();
ServiceMethod同样是通过Builder模式创建,所以我们同样分注释的2步去看ServiceMethod的创建.
1.1、构造Builder 所以我们先看ServiceMethod的Builder的构造,如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 static final class Builder <T , R > { final Retrofit retrofit; final Method method; final Annotation[] methodAnnotations; final Annotation[][] parameterAnnotationsArray; final Type[] parameterTypes; Builder(Retrofit retrofit, Method method) { this .retrofit = retrofit; this .method = method; this .methodAnnotations = method.getAnnotations(); this .parameterTypes = method.getGenericParameterTypes(); this .parameterAnnotationsArray = method.getParameterAnnotations(); }
构造中依此获取方法的注解、参数类型、参数的注解并依此赋值给methodAnnotations、parameterAnnotationsArray、parameterTypes,注意parameterAnnotationsArray是一个二维数组,因为一个参数可以被多个注解修饰,一个注解可以修饰多个参数。
1.2、创建ServiceMethod实例 我们接着看Builder的build方法,如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 static final class Builder <T , R > { final Retrofit retrofit; final Method method; final Annotation[] methodAnnotations; final Annotation[][] parameterAnnotationsArray; final Type[] parameterTypes; Type responseType; ParameterHandler<?>[] parameterHandlers; Converter<ResponseBody, T> responseConverter; CallAdapter<T, R> callAdapter; public ServiceMethod build () { callAdapter = createCallAdapter(); responseType = callAdapter.responseType(); responseConverter = createResponseConverter(); for (Annotation annotation : methodAnnotations) { parseMethodAnnotation(annotation); } int parameterCount = parameterAnnotationsArray.length; parameterHandlers = new ParameterHandler<?>[parameterCount]; for (int p = 0 ; p < parameterCount; p++) { Type parameterType = parameterTypes[p]; Annotation[] parameterAnnotations = parameterAnnotationsArray[p]; parameterHandlers[p] = parseParameter(p, parameterType, parameterAnnotations); } return new ServiceMethod<>(this ); }
build方法里面分4步,我们先看注释1、2,注释1调用createCallAdapter方法创建网络请求适配器CallAdapter,并赋值给callAdapter字段,createCallAdapter方法如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 private CallAdapter<T, R> createCallAdapter () { Type returnType = method.getGenericReturnType(); Annotation[] annotations = method.getAnnotations(); try { return (CallAdapter<T, R>) retrofit.callAdapter(returnType, annotations); } } public CallAdapter<?, ?> callAdapter(Type returnType, Annotation[] annotations) { return nextCallAdapter(null , returnType, annotations); } public CallAdapter<?, ?> nextCallAdapter(@Nullable CallAdapter.Factory skipPast, Type returnType, Annotation[] annotations) { int start = callAdapterFactories.indexOf(skipPast) + 1 ; for (int i = start, count = callAdapterFactories.size(); i < count; i++) { CallAdapter<?, ?> adapter = callAdapterFactories.get(i).get(returnType, annotations, this ); if (adapter != null ) { return adapter; } }
createCallAdapter方法中,获取到方法的返回值类型(如Call类型)和注解信息后,就调用Retrofit的callAdapter方法,callAdapter方法就调用nextCallAdapter方法,在nextCallAdapter方法中,会遍历Retrofit的网络请求适配器工厂callAdapterFactories,把方法的返回值returnType和注解信息annotations传进每个Factory的get方法中,看某个Factory是否愿意处理这个方法,如果愿意,就为这个方法创建对应CallAdapter实例,在Android平台中,CallAdapterFactor的默认实现是ExecutorCallAdapterFactory,ExecutorCallAdapterFactory的get方法返回一个CallAdapter匿名实现类。(查看前面讲过的Retrofit相关类介绍,里面有对ExecutorCallAdapterFactory的详细介绍)
我们再看build方法里的注释2,注释2调用createResponseConverter方法创建网络返回数据的数据转化器Converter,赋值给responseConverter字段,createResponseConverter方法如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 private Converter<ResponseBody, T> createResponseConverter () { Annotation[] annotations = method.getAnnotations(); try { return retrofit.responseBodyConverter(responseType, annotations); } } public <T> Converter<ResponseBody, T> responseBodyConverter (Type type, Annotation[] annotations) { return nextResponseBodyConverter(null , type, annotations); } public <T> Converter<ResponseBody, T> nextResponseBodyConverter ( @Nullable Converter.Factory skipPast, Type type, Annotation[] annotations) { 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 ) { return (Converter<ResponseBody, T>) converter; } } }
createResponseConverter方法中的流程和createCallAdapter方法的流程差不多,最终是遍历Retrofit的数据转化器工厂converterFactories,把该方法的返回值的泛型类型(如Call,泛型类型就是ResponseBody类型)和注解信息annotations传给每个Factory的responseBodyConverter方法中,看某个Factory是否愿意处理这个方法,如果愿意,就为这个方法创建对应的网络返回数据的数据转化器Converter实例,在Android平台中ConverterFactory的默认实现是BuiltInConverters(查看前面讲过的Retrofit相关类介绍,里面有对BuiltInConverters的详细介绍) 。有ResponseConverter就有相应的RequestConverter,RequestConverter用来处理网络请求数据的数据转化,RequestConverter并不在ServiceMethod的build方法中创建,而是在parseParameter方法中创建。
至于build方法的注释3、4的parseMethodAnnotation方法和parseParameter方法,限于篇幅,就留给大家自己探索了,我讲一下里面的大体逻辑:
parseMethodAnnotation方法 :该方法里面首先判断是哪种HTTP请求的注解,然后为不同的HTTP请求注解调用parseHttpMethodAndPath方法,该方法里面会获取注解中省略域名的Url和把Url里面需要替换地方用正则找出来放到一个Set中,如:@GET(“users/{user}”),省略域名的Url = users/{user},需要替换的地方是{user},把user找出来,最终parseMethodAnnotation方法获取到的信息是: HTTP请求方式、省略域名的Url和Url中需要替换值的地方 。
parseParameter方法 :这个方法是解析方法参数的注解,如@Quary、@Path等,里面会判断是哪种类型的注解,根据不同类型的注解,取出注解中的值,创建一个RequestConverter实例,最后把注解的值和RequestConverter实例传进ParameterHandler构造,为这个注解创建一个ParameterHandler实例返回 ,不同的注解有不同的ParameterHandler类型,如@Quary就有ParameterHandler.Quary,@Path就有ParameterHandler.Path。
都是通过注解解析出注解参数,然后一并封装到ServiceMethod中去,build方法执行完毕,就创建了一个ServiceMethod实例返回。
我们来小结一下ServiceMethod的创建过程:
经过这2步后,为这个方法method创建了一个对应的ServiceMethod实例,这个ServiceMethod封装了网络请求所需要的所有参数和持有CallAdapter实例、处理网络返回数据转化的Converter实例,同时这个ServiceMethod是一个单例,也就是说Api接口里的每一个方法都分别对应着一个ServiceMethod实例,这个ServiceMethod实例持有着网络请求所需要的所有参数 。
我们继续回到loadServiceMethod方法中。
2、小结 调用loadServiceMethod方法后,创建了一个ServiceMethod实例并缓存到一个Map中,第二次使用时直接从缓存获取ServiceMethod实例,不必重复创建,提高效率。
我们回到invoke方法,有了ServiceMethod实例后,就可以创建一个okHttpCall实例.
注释2、创建一个okHttpCall实例 1 2 OkHttpCall<Object> okHttpCall = new OkHttpCall<>(serviceMethod, args);
OkHttpCall的构造如下:
1 2 3 4 5 6 7 8 9 10 11 12 final class OkHttpCall <T > implements Call <T > { private final ServiceMethod<T, ?> serviceMethod; private final @Nullable Object[] args; private @Nullable okhttp3.Call rawCall; OkHttpCall(ServiceMethod<T, ?> serviceMethod, @Nullable Object[] args) { this .serviceMethod = serviceMethod; this .args = args; }
可以看到Okhttp把刚刚得到的ServiceMethod实例和接口方法的参数保存起来,OkHttpCall在前面的Retrofit的相关类介绍已经简单介绍过了,它就是实现了Call的一个类,它里面的方法大部分逻辑都转发给Okhttp的Call 。
得到okHttpCall实例后,通过adapt方法把它适配成另外一个Call.
注释3、把OkHttpCall适配成另一个Call 1 2 return serviceMethod.adapt(okHttpCall);
ServiceMethod的adapt方法如下:
1 2 3 4 T adapt (Call<R> call) { return callAdapter.adapt(call); }
adapt方法传进来的call是OkhttpCall实例,callAdapter就是刚刚用createCallAdapter方法创建的CallAdapter实例,在Android平台中,这个CallAdapter实例的adapt方法的默认实现就是用ExecutorCallbackCall包装传进来的OkHttpCall,并返回ExecutorCallbackCall实例,如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 final class ExecutorCallAdapterFactory extends CallAdapter .Factory { final Executor callbackExecutor; ExecutorCallAdapterFactory(Executor callbackExecutor) { this .callbackExecutor = callbackExecutor; } @Override public CallAdapter<?, ?> get(Type returnType, Annotation[] annotations, Retrofit Retrofit) { final Type responseType = Utils.getCallResponseType(returnType); return new CallAdapter<Object, Call<?>>() { @Override public Type responseType () { return responseType; } @Override public Call<Object> adapt (Call<Object> call) { return new ExecutorCallbackCall<>(callbackExecutor, call); } }; } static final class ExecutorCallbackCall <T > implements Call <T > { } }
所以callAdapter.adapt(call)就是把OkhttpCall 适配成 ExecutorCallbackCall ,我们来看一下ExecutorCallbackCall,它是ExecutorCallAdapterFactory的内部类,如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 static final class ExecutorCallbackCall <T > implements Call <T > { final Executor callbackExecutor; final Call<T> delegate; ExecutorCallbackCall(Executor callbackExecutor, Call<T> delegate) { this .callbackExecutor = callbackExecutor; this .delegate = delegate; } @Override public void enqueue (final Callback<T> callback) { checkNotNull(callback, "callback == null" ); delegate.enqueue(new Callback<T>() { @Override public void onResponse (Call<T> call, final Response<T> response) { callbackExecutor.execute(new Runnable() { @Override public void run () { if (delegate.isCanceled()) { callback.onFailure(ExecutorCallbackCall.this , new IOException("Canceled" )); } else { callback.onResponse(ExecutorCallbackCall.this , response); } } }); } @Override public void onFailure (Call<T> call, final Throwable t) { callbackExecutor.execute(new Runnable() { @Override public void run () { callback.onFailure(ExecutorCallbackCall.this , t); } }); } }); } @Override public Response<T> execute () throws IOException { return delegate.execute(); } }
可以看到,ExecutorCallbackCall和OkhttpCall一样都实现了Call接口中的方法,并且ExecutorCallbackCall中持有OkhttpCall的实例,它的enqueue方法和execute方法都委托给OkhttpCall的enqueue方法和execute方法执行,当网络数据返回时,通过线程切换执行器callbackExecutor,切换到主线程执行callback回调,这里采用了装饰者模式 ,采用装饰者模式的好处就是不用通过继承就可以扩展一个对象的功能,动态的给一个对象添加一些额外的操作 ,这里额外的操作就是通过线程切换执行器切换回主线程后再执行callback回调,因为OkHttpCall的enqueue方法是进行网络的异步请求,当异步请求结果返回时,回调是在子线程中,需要通过线程切换执行器转换到主线程中再进行callback回调。
最终,ServiceMethod的adapt方法把OkhttpCall 适配成不同平台的网络请求执行器,并返回 ,在Android平台中,OkhttpCall 适配成了 ExecutorCallbackCall实例。
4、小结 当我们调用Api接口实例中的方法时,这些方法的处理逻辑都会转发给invoke方法,在invoke方法中,会为每一个方法创建一个ServiceMethod,这个ServiceMethod封装了网络请求所需要的所有参数和持有CallAdapter实例、处理网络返回数据转化的Converter实例,接着就会把这个ServiceMethod实例和接口方法的参数传进OkhttpCall的构造中,创建一个OkhttpCall实例,接着把这个OkhttpCall实例传给ServiceMethod的adapt方法,ServiceMethod的adapt方法就会调用CallAdapter实例的adapt方法,把OkhttpCall适配成不同平台的网络请求执行器,所以如果你添加了其他平台的CallAdapterFactory,你就可以得到不同平台下的网络请求执行器,在Android平台中,CallAdapter实例的adapt方法会把OkhttpCall适配成ExecutorCallbackCall,这个ExecutorCallbackCall持有OkhttpCall实例和线程切换器MainThreadExecutor实例,当我们发起网络请求时,ExecutorCallbackCall就会委托OkhttpCall发起网络请求,当网络请求数据返回时,ExecutorCallbackCall就会通过MainThreadExecutor把线程切换主线程执行回调。
得到网络请求执行器之后,就可以发起,网络请求了.
六、发起网络请求(以异步为例) 不同平台下的网络请求执行器不同,在Android平台,调用Api接口实例的方法后返回的是ExecutorCallbackCall,有了ExecutorCallbackCall后,我们就可以发起同步或异步请求,同步和异步请求的流程类型,唯一不同的是异步请求需要把结果通过Callback回调给上层,而同步请求则是直接return结果给上层。
下面以异步请求为例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 call.enqueue(new Callback<ResponseBody>() { @Override public void onResponse (Call<ResponseBody> call, Response<ResponseBody> response) { ResponseBody body = response.body(); try { Log.d(TAG, "请求结果:" + body.string()); } catch (IOException e) { e.printStackTrace(); } } @Override public void onFailure (Call<ResponseBody> call, Throwable t) { } });
调用的是ExecutorCallbackCall的enqueue方法,如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 public void enqueue (final Callback<T> callback) { checkNotNull(callback, "callback == null" ); delegate.enqueue(new Callback<T>() { @Override public void onResponse (Call<T> call, final Response<T> response) { callbackExecutor.execute(new Runnable() { @Override public void run () { if (delegate.isCanceled()) { callback.onFailure(ExecutorCallbackCall.this , new IOException("Canceled" )); } else { callback.onResponse(ExecutorCallbackCall.this , response); } } }); } @Override public void onFailure (Call<T> call, final Throwable t) { callbackExecutor.execute(new Runnable() { @Override public void run () { callback.onFailure(ExecutorCallbackCall.this , t); } }); } });
调用的是OkhttpCall的enqueue方法,如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 private @Nullable okhttp3.Call rawCall;public void enqueue (final Callback<T> callback) { checkNotNull(callback, "callback == null" ); okhttp3.Call call; Throwable failure; synchronized (this ) { if (executed) throw new IllegalStateException("Already executed." ); executed = true ; call = rawCall; failure = creationFailure; if (call == null && failure == null ) { try { call = rawCall = createRawCall(); } catch (Throwable t) { throwIfFatal(t); failure = creationFailure = t; } } } if (failure != null ) { callback.onFailure(this , failure); return ; } if (canceled) { call.cancel(); } call.enqueue(new okhttp3.Callback() { @Override public void onResponse (okhttp3.Call call, okhttp3.Response rawResponse) { Response<T> response; try { response = parseResponse(rawResponse); } catch (Throwable e) { callFailure(e); return ; } try { callback.onResponse(OkHttpCall.this , response); } catch (Throwable t) { t.printStackTrace(); } } @Override public void onFailure (okhttp3.Call call, IOException e) { callFailure(e); } private void callFailure (Throwable e) { try { callback.onFailure(OkHttpCall.this , e); } catch (Throwable t) { t.printStackTrace(); } } }); }
OkhttpCall的enqueue方法大体分为3步:
1、获取Okhttp的Call实例,赋值给临时变量call:
1.1、如果是第一次发起网络请求,就调用createRawCall方法就创建来自Okhttp的Call,赋值给临时变量call和成员变量rawCall;
1.2、如果不是第一次发起网络请求,就把上次的rawCall实例赋值给临时变量call.
2、调用Okhttp的Call的enqueue方法发起异步请求(更多细节请查看上一篇文章okhttp3源码分析之请求流程 );
3、当网络请求结果正确返回时,用parseResponse方法把Okhttp的Response解析成Retrofit的Response.
所以我们来看一下两个关键的办法,createRawCall方法和parseResponse方法:
1、创建Okhttp的Call createRawCall方法如下:
1 2 3 4 5 6 7 8 9 10 private okhttp3.Call createRawCall () throws IOException { okhttp3.Call call = serviceMethod.toCall(args); if (call == null ) { throw new NullPointerException("Call.Factory returned null." ); } return call; }
createRawCall方法调用ServiceMethod的toCall方法,如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 okhttp3.Call toCall (@Nullable Object... args) throws IOException { RequestBuilder requestBuilder = new RequestBuilder(httpMethod, baseUrl, relativeUrl, headers, contentType, hasBody, isFormEncoded, isMultipart); ParameterHandler<Object>[] handlers = (ParameterHandler<Object>[]) parameterHandlers; int argumentCount = args != null ? args.length : 0 ; for (int p = 0 ; p < argumentCount; p++) { handlers[p].apply(requestBuilder, args[p]); } return callFactory.newCall(requestBuilder.build()); }
首先创建一个用于构造Request的requestBuilder,并把ServiceMethod中封装的参数传进去,然后遍历每个方法参数的ParameterHandler,通过apply方法取出ParameterHandler中的参数放入requestBuilder中,ParameterHandler前面讲过,它里面保存了每个方法参数的注解的值和处理这些值的Converter实例,构造Request的参数都有了,接着就通过requestBuilder.build方法创建一个Okhttp的Request实例并传进newCall方法,最后通过OkHttpClient的newCall方法创建一个Okhttp的Call实例返回。
最终createRawCall方法返回一个来自Okhttp的Call实例。
2、解析返回结果 parseResponse方法如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 Response<T> parseResponse (okhttp3.Response rawResponse) throws IOException { ResponseBody rawBody = rawResponse.body(); ExceptionCatchingRequestBody catchingBody = new ExceptionCatchingRequestBody(rawBody); try { T body = serviceMethod.toResponse(catchingBody); return Response.success(body, rawResponse); } }
首先把Okhttp的Response的body取处理,然后用ExceptionCatchingRequestBody包装一下,这个ExceptionCatchingRequestBody是继承自Okhttp的ResponseBody,接着把这个ResponseBody传进ServiceMethod的toResponse方法,里面会使用ServiceMethod保存的处理网络返回数据的Converter实例来把这个ResponseBody转化成我们需要的数据类型,ServiceMethod的toResponse方法如下:
1 2 3 4 R toResponse (ResponseBody body) throws IOException { return responseConverter.convert(body); }
这个responseConverter就是在创建ServiceMethod时用createResponseConverter方法创建的Converter实例,把body转化成R类型,不同的数据转化有不同的实现,在Retrofit的默认实现中,它就是直接返回ResponseBody。
我们再回到parseResponse方法,调用完ServiceMethod的toResponse方法,得到了转化后的body,最后调用了Response的success方法,把Okhttp的Response和转化后的body传了进去,最终返回一个Retrofit的Response。
3、小结 以异步为例,Retrofit通过ExecutorCallbackCall的enqueue方法发起网络请求,最终会通过OkhttpCall的enqueue方法来发起网络请求,OkhttpCall的enqueue方法中,首先会调用创建一个来自Okhttp的Call实例,然后通过这个Okhttp的Call实例的enqueue方法来发起异步请求,当网络结果Okhttp的Response返回时,调用parseResponse方法解析Response,parseResponse方法里面还会调用ServiceMethod的toResponse方法通过Converter实例的convert方法把ResponseBody转化成我们想要的数据,不同的数据转化有不同的实现,在Retrofit的默认实现中,它就是直接返回Okhttp的ResponseBody,最后把这个转化后的body和原始的Okhttp的Response一并封装成Retrofit的Response返回,最后把parseResponse方法返回的Response通过callback回调出去,这时ExecutorCallbackCall收到回调,通过线程切换执行器callbackExecutor,切换到主线程执行callback回调,一次异步请求就完成了,同步请求也是大同小异,只是少了个回调,就留给大家自己分析了。
总结 能够阅读到这里,说明你对Retrofit的理解又更上一层楼了,其实从整体去看Retrofit,它的流程并不复杂,它的使用也非常的简单,这得益于它优秀的架构,和运用得当的设计模式,其中最核心的当属动态代理模式,通过一个代理类InvocationHandler代理N多个接口,它把每一个方法的处理逻辑都集中到了invoke方法中,这样就能在同一处地方处理所有方法的注解解析,还有它那面向接口的设计,使得各个子模块之间降低耦合,让我们以最小的代价替换成我们需要的实现,Retrofit的整体流程图如下:
一句话概括Retrofit:它是一个通过动态代理把Api接口方法的注解解析成网络请求所需参数,最后通过Okhttp执行网络请求的封装库。
以上就是本文的所有内容,如有错误,欢迎指出。
参考资料:
Retrofit解析之面向接口编程