一:Retrofit是什么?
准确来说,Retrofit 是一个 RESTful 的 HTTP 网络请求框架的封装。
原因:网络请求的工作本质上是 OkHttp 完成,而 Retrofit 仅负责 网络请求接口的封装
我们先来看看下面这个图:

上图说明了如下几点:
1. App应用程序通过 Retrofit 请求网络,实际上是使用 Retrofit 接口层封装请求参数、Header、Url 等信息,之
后由 OkHttp 完成后续的请求操作。
2. 在服务端返回数据之后,OkHttp 将原始的结果交给 Retrofit,Retrofit根据用户的需求对结果进行解析。
所以,网络请求的本质仍旧是OkHttp完成的,retrofit只是帮使用者来进行工作简化的,比如配置网络,处理数据等
工作,提高这一系列操作的复用性。这也就是网上流行的一个不太准确的总结:okhttp是瑞士军刀,retrofit则是讲这
边瑞士军刀包装从了一个非常好用的指甲钳。

二: Retrofit 对Okhttp做了什么
Retrofit并没有改变网络请求的本质,也无需改变,因为Okhttp已经足够强大,Retrofit的封装可以说是很强大,里
面涉及到一堆的设计模式,可以通过注解直接配置请求,可以使用不同的http客户端,虽然默认是用http ,可以使用
不同Json Converter 来序列化数据,同时提供对RxJava的支持,使用Retrofit + OkHttp + RxJava 可以说是目前比较
潮的一套框架,但是需要有比较高的门槛。
下面我们来对比一下OKhttp网络请求和 retrofit网络请求的区别。

2.1. Okhttp请求总结
[大家先看下面okhttp请求的样例代码]

private void testOkHttp() throws IOException {//Step1final OkHttpClient client = new OkHttpClient();//Step2final Request request = new Request.Builder().url("https://www.google.com.hk").build();//Step3Call call = client.newCall(request);//step4 发送网络请求,获取数据,进行后续处理call.enqueue(new Callback() {@Overridepublic void onFailure(Call call, IOException e) {}@Overridepublic void onResponse(Call call, Response response) throws IOException {Log.i(TAG,response.toString());Log.i(TAG,response.body().string());}});}

「解析一下上面的代码」
Step1:创建HttpClient对象,也就是构建一个网络类型的实例,一般会将所有的网络请求使用同一个单例对象。
Step2:构建Request,也就是构建一个具体的网络请求对象,具体的请求url,请求头,请求体等等。
Step3:构建请求Call,也就是将具体的网络请求与执行请求的实体进行绑定,形成一个具体的正式的可执行实体。
Step4: 后面就进行网络请求了,然后处理网络请求的数据了。
「总结一下」
OKhttp的意义:OkHttp 是基于Http协议封装的一套请求客户端,虽然它也可以开线程,但根本上它更偏向真正的
请求,跟HttpClient, HttpUrlConnection的职责是一样的。
Okhttp的职责:OkHttp主要负责socket部分的优化,比如多路复用,buffer缓存,数据压缩等等。
Okhttp给用户留下的问题:
1)用户网络请求的接口配置繁琐,尤其是需要配置请求body,请求头,参数的时候;
2)数据解析过程需要用户手动拿到responsbody进行解析,不能复用;
3)无法适配自动进行线程的切换。
那么这几个问题谁来解决? 对,retrofit!

2.2 Retrofit请求总结
【Retrofit 进行网络请求的流程样板代码】

//step1
Retrofit retrofit = new Retrofit.Builder().baseUrl("https://www.wanandroid.com/").addConverterFactory(GsonConverterFactory.create(new Gson())).build();
//step2
ISharedListService sharedListService =  retrofit.create(ISharedListService.class);
//step3
Call<SharedListBean> sharedListCall = sharedListService.getSharedList(2,1);
//step4
sharedListCall.enqueue(new Callback<SharedListBean>() {@Overridepublic void onResponse(Call<SharedListBean> call, Response<SharedListBean> response{if (response.isSuccessful()) {System.out.println(response.body().toString());}}@Overridepublic void onFailure(Call<SharedListBean> call, Throwable t) {t.printStackTrace();}
});

Step1: 创建retrofit对象, 构建一个网络请求的载体对象,和okhttp构建OkhttpClient对象有一样的意义,只不过
retrofit在build的时候有非常多的初始化内容,这些内容可以为后面网络请求提供准备,如准备 现成转换Executor,
Gson convert,RxJavaCallAdapter。
Step2:Retrofit的精髓,为统一配置网络请求完成动态代理的设置。
Step3:构建具体网络请求对象Request(service),在这个阶段要完成的任务:1)将接口中的注解翻译成对应的
参数;2)确定网络请求接口的返回值response类型以及对应的转换器;3)讲Okhttp的Request封装成为Retrofit的
OKhttpCall。总结来说,就是根据请求service 的Interface来封装Okhttp请求Request。
Step4:后面就进行网络请求了,然后处理网络请求的数据了
2.3「总结一下」
Retrofit主要负责应用层面的封装,就是说主要面向开发者,方便使用,比如请求参数,响应数据的处理,错误处理
等等。
Retrofit封装了具体的请求,线程切换以及数据转换。
网上一般都推荐RxJava+Retrofit+OkHttp框架,Retrofit负责请求的数据和请求的结果,使用接口的方式呈现,
OkHttp负责请求的过程,RxJava负责异步,各种线程之间的切换,用起来非常便利。
小结:
通过下图,让我们来总结一下,retrofit是如何来封装okhttp请求的。

大体的网络流程是一致的,毕竟都是通过okhttp进行网络请求。主要的步骤都是:创建网络请求实体client->构建真
正的网络请求-> 将网络请求方案与真正的网络请求实体结合构成一个请求Call->执行网络请求->处理返回数据->处理
Android 平台的线程问题。
在上图中,我们看到的对比最大的区别是什么?
0)okhttp创建的是OkhttpClient,然而retrofit创建的是 Retrofit实例
1)构建蓝色的Requet的方案,retrofit是通过注解来进行的适配
2)配置Call的过程中,retrofit是利用Adapter适配的Okhttp 的Call
3)相对okhttp,retrofit会对responseBody进行 自动的Gson解析
4)相对okhttp,retrofit会自动的完成线程的切换。
那么retrofit是如何完成这几点的封装的呢?请看下面的文章

三: Retrofit的构建过程
Retrofit通过build模式来生成一个Retrofit对象,通过代码我们知道,Retrofit默认会使用OkHttp来发送网络请求,当
然,我们也可以自己定制。
「看下面的代码」

public Retrofit build() {if (baseUrl == null) {throw new IllegalStateException("Base URL required.");}// 代码1//默认只支持okhttp请求,不支持 httpurlconnection 和 httpclientokhttp3.Call.Factory callFactory = this.callFactory;if (callFactory == null) { callFactory = new OkHttpClient();}// 代码2// 添加一个线程管理 Executor,okhttp 切换线程需要手动操作,但是retrofit// 不需要,就是因为这个Executor 的存在,其实他是handlerExecutor callbackExecutor = this.callbackExecutor;if (callbackExecutor == null) {callbackExecutor = platform.defaultCallbackExecutor();}//代码3    // Make a defensive copy of the adapters and add the default Call adapter.List<CallAdapter.Factory> adapterFactories = new ArrayList<>(this.adapterFactories);adapterFactories.add(platform.defaultCallAdapterFactory(callbackExecutor));// Make a defensive copy of the converters.List<Converter.Factory> converterFactories = new ArrayList<>
(this.converterFactories);return new Retrofit(callFactory, baseUrl, unmodifiableList(converterFactories),unmodifiableList(callAdapterFactories), callbackExecutor, validateEagerly);
}

1:在代码 1 处
初始化 构建call 的工厂,但是这个地方直接就是使用了 okhttp的call,没有使用到工厂设计模式去添加构建
httpclient 或者 httpurlconnection的方法来创建 call,说明retrofit 已经铁下心只支持okhttp创建call请求了。
那么call 是什么的抽象呢?看下面的代码,okhttp请求的代码

OkHttpClient client = new OkHttpClient.Builder().readTimeout(5, TimeUnit.SECONDS).build();
Request request = new Request.Builder().url("http://www.baidu.com").get().build();
okhttp3.Call call = client.newCall(request);
call.enqueue(new okhttp3.Callback() )...

OkHttpClient是 http 请求的载体包含socket等可以复用的对象,协议配置等等一切。
Request 创建的是一个具体的有url,header,等请求信息的一个网络请求,表示这个具体的请求。
Call 通往请求的,去执行请求的整个过程的一个抽象。也是进行网络请求的最终接口。
所以,此次调用,目的就是创建了一个OkHttpClient,换句话说,这里的调用就是生产 Okhttp网络请求需要的请
求Call的,以备后面进行真正的网络请求。
2:在代码2处
网络请求需要在子线程中执行,那么就需要线程管理,所以就有了代码2的存在,深入源码后发现,这个地方就是运
用handler进行线程切换,当网络请求回来了进行线程切换,可以看下面的源码

static final class Android extends Platform {Android() {super(Build.VERSION.SDK_INT >= 24);}@Override public Executor defaultCallbackExecutor() {return new MainThreadExecutor();}static class MainThreadExecutor implements Executor {private final Handler handler = new Handler(Looper.getMainLooper());@Override public void execute(Runnable r) {handler.post(r);}}
}

所以,此次调用,目的是构建一个用handler封装的Executor,以备后面进行网络请求成功后的线程切换用
3:在代码3处
设置默认CallAdapterFactory

在此添加的CallAdapterFactory属于系统默认的,当然,我们可以添加RxJavaCallAdapterFactory。默认的
CallAdapterFactory是 ExecutorCallAdapterFactory 类的对象,在Platform.java Class里面可以梳理出来

defaultCallAdapterFactory(Executor callbackExecutor) {return new ExecutorCallAdapterFactory(callbackExecutor);
}

所以构建的Retrofit都是用于进行后面请求的需要的内容的一个准备工作。也就是封装Okhttp需要的准备工作。

四: Retrofit构建 IxxxService 对象的过程
(Retrofit.create())
看下面的代码:

ISharedListService sharedListService =  retrofit.create(ISharedListService.class);
Call<SharedListBean> sharedListCall = sharedListService.getSharedList(2,1);

上面两行代码需要连起来才能正确的被阅读,因为,在create里面是使用了动态代理的技术方案,而动态代理是运行
时生效的,当我们看到看到create的时候只
create的代码如下:

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 final Platform platform = Platform.get();@Overridepublic Object invoke(Object proxy, Method method, @Nullable Object[] args)throws Throwable {// If the method is a method from Object then defer to normal invocation.if (method.getDeclaringClass() == Object.class) {return method.invoke(this, args);}if (platform.isDefaultMethod(method)) {return platform.invokeDefaultMethod(method, service, proxy, args);}// 根据方法生成一个ServiceMethod对象(内部会将生成的ServiceMethod放入在缓存中,//如果已经生成过则直接从缓存中获取)ServiceMethod<Object, Object> serviceMethod =(ServiceMethod<Object, Object>) loadServiceMethod(method); // 根据ServiceMethod对象和请求参数生成一个OkHttpCall对象,这个OkHttpCall能够//调用OkHttp的接口发起网络请求OkHttpCall<Object> okHttpCall = new OkHttpCall<>(serviceMethod, args);// 调用serviceMethod的callAdapter的adapt方法,并传入okHttpCall,返回一个对象,//这个的目的主要是为了适配返回类型,其内部会对OkhttpCall对象进行包装return serviceMethod.callAdapter.adapt(okHttpCall);}});
}

1)Retrofit的create方法通过动态代理的模式,生成了实现了具体的网络请求接口的对象,并在InvocationHandler
的invoke方法中统一处理网络请求接口实体对象的方法;2)invoke方法会通过方法构造一个ServiceMethod对象,
并将其放入缓存中;3)然后根据ServiceMethod对象和网络请求的参数args去构造一个OkHttpCall对象;4)最后
调用serviceMethod的callAdapter的adapt方法,传入将OkHttpCall对象,callAdapter的目的主要是为了适配
OkHttpCall对象,其内部会对OkHttpCall对象进行包装,生成对应返回类型的对象。

4.1 动态代理
动态代理的原理主要是在运行时动态生成代理类,然后根据代理类生成一个代理对象,在这个代理对象的方法中中又
会调用InvocationHandler的invoke来转发对方法的处理。
那么大家一定要关注一个细节,我们在使用retrofit的时候,对每一个网络请求的产生都必须要先调用create函数,也
就是意味着,我们的请求都是通过代理类来进行处理的。但是代理类具体的代理行为是发生在哪里呢?很显然,他并
不是在create函数执行的时候,而是在使用具体的接口创建具体网络请求Call的时候,当调用具体网络请求Call的代
码示例如下:

Call<SharedListBean> sharedListCall = sharedListService.getSharedList(2,1);

在执行上面的代码的时候,它会走代理设计模式的InvocationHandler里面的invoke()函数,也就是所有的网络请求
在创建具体网络请求Call的时候,都会走Invoke,从而我们可以在invoke里面进行各种行为的统一处理,比如:接口
的统一配置,也就是注解的解读和网络请求参数的拼接。

4.2 ServiceMethod
大家先看看loadServiceMethod方法

ServiceMethod loadServiceMethod(Method method) {ServiceMethod result;synchronized (serviceMethodCache) {
// 为什么会缓存?为了效率result = serviceMethodCache.get(method);if (result == null) {result = new ServiceMethod.Builder(this, method).build();serviceMethodCache.put(method, result);}}return result;
}

loadServiceMethod首先会从缓存中获取ServiceMethod对象,如果没有,则通过Method和Retrofit对象构造一个
ServiceMethod对象,并将其放入缓存中。
[一个细节]

每一个method 都有一个自己的ServiceMethod,这就意味着ServiceMethod是属于函数的,而不是类的。也就是我
们定义的网络访问接口类,在接口类里面的每一个函数都会在反射阶段形成自己的serviceMethod。那么
ServiceMethod是什么呢?
ServiceMethod其实是用来存储一次网络请求的基本信息的,比如Host、URL、请求方法等,同时ServiceMethod还
会存储用来适配OkHttpCall对象的CallAdpater。ServiceMethod的build方法会解读传入的Method,首先
ServiceMethod会在CallAdpaterFactory列表中寻找合适的CallAdapter来包装OkHttpCall对象,这一步主要是根据
Method的返回参数来匹配的,比如如果方法的返回参数是Call对象,那么ServiceMethod就会使用默认的
CallAdpaterFactory来生成CallAdpater,而如果返回对象是RxJava的Obserable对象,则会使用
RxJavaCallAdapterFactory提供的CallAdpater。然后build方法会解读Method的注解,来获得注解上配置的网络请
求信息,比如请求方法、URL、Header等

public ServiceMethod build() {callAdapter = createCallAdapter(); // 查找能够适配返回类型的CallAdpaterresponseType = callAdapter.responseType();if (responseType == Response.class || responseType == okhttp3.Response.class) {throw methodError("'"+ Utils.getRawType(responseType).getName()+ "' is not a valid response body type. Did you mean ResponseBody?");}//设置请求的数据适配器converterresponseConverter = createResponseConverter();// 解读方法的注解for (Annotation annotation : methodAnnotations) {parseMethodAnnotation(annotation);}if (httpMethod == null) {throw methodError("HTTP method annotation is required (e.g., @GET, @POST, etc.).");}if (!hasBody) {if (isMultipart) {throw methodError("Multipart can only be specified on HTTP methods with request body (e.g.,
@POST).");}if (isFormEncoded) {throw methodError("FormUrlEncoded can only be specified on HTTP methods with "+ "request body (e.g., @POST).");}}int parameterCount = parameterAnnotationsArray.length;parameterHandlers = new ParameterHandler<?>[parameterCount];for (int p = 0; p < parameterCount; p++) {Type parameterType = parameterTypes[p];if (Utils.hasUnresolvableType(parameterType)) {throw parameterError(p, "Parameter type must not include a type variable or
wildcard: %s",parameterType);}Annotation[] parameterAnnotations = parameterAnnotationsArray[p];if (parameterAnnotations == null) {throw parameterError(p, "No Retrofit annotation found.");}parameterHandlers[p] = parseParameter(p, parameterType, parameterAnnotations);}if (relativeUrl == null && !gotUrl) {throw methodError("Missing either @%s URL or @Url parameter.", httpMethod);}if (!isFormEncoded && !isMultipart && !hasBody && gotBody) {throw methodError("Non-body HTTP method cannot contain @Body.");}if (isFormEncoded && !gotField) {throw methodError("Form-encoded method must contain at least one @Field.");}if (isMultipart && !gotPart) {throw methodError("Multipart method must contain at least one @Part.");}return new ServiceMethod<>(this);}

4.3 okHttpCall

OkHttpCall<Object> okHttpCall = new OkHttpCall<>(serviceMethod, args);

我们知道,ServiceMethod封装了网络请求的基本信息,比如Host、URL等,我们根据ServiceMethod和请求参数
args就可以确定本次网络请求的所有信息了,OkHttpCall主要是将这些信息封装起来,并调用OkHttp的接口去发送
网络请求,这里,我们就将OkHttpCall看成是一个处理网络请求的类即可。
4.4 callAdapter
在retrofit中,invoke() 里面的最后一行代码,

return serviceMethod.callAdapter.adapt(okHttpCall);

那么我们可以设想一下为什么Retrofit还要设计一个CallAdapter接口呢?
先来说一个客观事实,Retrofit真正使用Okhttp进行网络请求的就是OkHttpCall这个类
曾提到了Call对象的创建是通过是通过ServiceMethod.adapt()完成的,这里在看看该方法的源码:
ServiceMethod.adapt()方法:

T adapt(Call<R> call) {return callAdapter.adapt(call);
}123

通过上述源码可知,最终Call对象是调用CallAdapter.adapt(Call)方法创建的,那么CallAdapter及具体的Call对象又
是如何生成的呢?
如果没有这个适配器模式,会出现什么情况?
很明显,没有适配器的时候此时我们网络请求的返回接口只能直接返回OkHttpCall,那么所有的网络请求都是用
okhttpCall进行,这样的话就失去了retrofit 封装网络请求call的意义了,譬如:rxjavaCallAdapterFactory 就没有办
法支持。
如果我们想要返回的不是Call呢?比如RxJava的Observable,这种情况下该 怎么办呢?
适配器模式在此发挥了其应用的作用!!!
将网络请求的核心类OkHttpCall进行适配,你需要什么类型的数据就通过适配器适配,返回适配后的对象就是了。
正是这种CallApdate接口的设计,使得我们在使用Retrofit的时候可以自定义我们想要的返回类型。此接口的设计也
为RxJava的扩展使用做了很好的基础!!!
更多关于CallAdapter在retrofit中的实现细节,大家可以看我的其他的文章。

五: Retrofit网络请求操作小结
一般的Retrofit网络请求的操作是指 Call.excute() & Call.enqueue()的过程,这个过程才是真正的网络请求,因为,
网络配置,请求地址配置,Call适配,网络请求 requestBody &返回值responseBody转化适配准备工作都已经完成。

sharedListCall.enqueue(new Callback()...);
sharedListCall.excute();

在进行网络请求的执行的时候,基本上就是调用,ServiceMethod中设置的各个内容如 :
1)OkHttpCall进行网络请求,实则是进行okhttp的网络请求;
2)利用 converter进行网络请求数据的转换,一般是Gson();
3)利用 rxjava observable构建 rxjava类型的责任链访问方案,并进行线程切换;
4) 如果没有rxjava的添加,那么就使用默认的callAdapter里面的callbackExecutor进行线程的切换
, 进行网络请求.
整体网络请求的流程图请看下图:

Retrofit详解相关推荐

  1. Retrofit详解(一)(Retrofit创建过程)

    作为一个coder 最悲哀的莫过于知其然,不知其所以然. 闲暇之余,研究研究Retrofit源码,为了防止大篇幅的代码,看得头晕眼花,这章仅仅详细介绍Retrofit 的创建过程.Retrofit使用 ...

  2. Retrofit详解(二)(Retrofit核心流程)

    上一章已经介绍了Retrofit创建过程,这章介绍Retrofit Api Service创建与访问过程. Retrofit 相比Volley等网络框架一个最大区别就是它只需要声明接口,就可以访问网络 ...

  3. Android Retrofit详解(retrofit:2.3.0)

    目录 1.Retrofit是什么? 2.Retrofit如何使用? 2.1创建HTTP请求的API接口 2.2请求执行 3.注解详情 3.1请求方法注解 3.2标记请求数据类型 3.3注解参数 4.G ...

  4. Retrofit 注解参数详解

    转载请标明出处:http://blog.csdn.net/zhaoyanjun6/article/details/121000230 本文出自[赵彦军的博客] 系列文章推荐: Android Flow ...

  5. Retrofit 基础+详解

    基础: 1.什么是retrofit retrofit是网络请求框架,可以理解为okHttp的加强版,底层封装了OKhttp.准确的是Retrofit是一个restful的http网络请求框架封装.因为 ...

  6. RxJava操作符在android中的使用场景详解(一)

    转载请注明出处:http://www.wangxinarhat.com/2016/04/19/2016-04-19-rxjava-android-operate1/ 最近学习了RxJava在andro ...

  7. Retrofit2 multpart多文件上传详解

    原文出处:http://www.chenkaihua.com/2016/04/02/retrofit2-upload-multipart-files.html Retrofit2是目前很流行的andr ...

  8. android gridview控件使用详解_作为Android 开发者该如何进阶?

    经常在简书和微信上收到一些同学的私信,说自己马上毕业或者已经毕业一年,从事Android开发相关的工作,现在不知道要学习什么东西了.或者说自己也在摸索着学习,但是不知道学习的路线对不对,感觉很迷茫,想 ...

  9. android ------- 开发者的 RxJava 详解

    在正文开始之前的最后,放上 GitHub 链接和引入依赖的 gradle 代码: Github:  https://github.com/ReactiveX/RxJava  https://githu ...

  10. retrofit2使用详解_秒懂Retrofit2之Converter

    >[版权申明]非商业目的注明出处可自由转载 博文地址:https://blog.csdn.net/ShuSheng0007/article/details/89675797 出自:shushe ...

最新文章

  1. ROI Align 在 R-FCN 中的推广:PSROI-Align(附代码)
  2. 计算机设计大赛海洋世界,全国大学生海洋文化设计大赛第二届获奖作品(三)...
  3. 无批次管理物料转成有批次管理物料的方案
  4. Service Mesh所应对的8项挑战
  5. ajax status php,解决laravel 出现ajax请求419(unknown status)的问题
  6. 【BZOJ1800】飞行棋,没有最好(ge pi)只有更好
  7. mac如何安装python_手把手教你安装Python开发环境(二)之Mac电脑安装Python解释器...
  8. java表达式7|3,Chapter3 Java运算符
  9. 关于Spring Cloud Config服务器介绍
  10. 区块链 以太坊 入门知识
  11. java变量的声明和数据类型
  12. 大连计算机类书店小结
  13. cnpack导致view快捷键失灵。
  14. 前端学习笔记-22-浏览器中的DOM操作
  15. 微星笔记本安装Ubuntu桌面版
  16. H265 CTU、CU、PU、TU划分的特点及要求
  17. 4399小游戏之三子棋(可联机)
  18. 微信小程序017音乐播放器系统 php java
  19. Pyspark学习笔记小总
  20. 怎样设置二维码的尺寸

热门文章

  1. php输入为空,ecshop搜索框内容为空提示用户输入内容
  2. pycharm 配置虚拟环境 安装虚拟环境
  3. IPQ4xx Ethernet Analysis
  4. 聚焦 | 山东省大数据的发展现状与规划
  5. Win10中英文切换 win键+空格
  6. walking机器人入门教程-单点导航
  7. 肤色冷暖色测试软件_认识你自己|肤色冷暖测试
  8. 几个南阳oj的STL题
  9. np.digitize 用法详解
  10. 从链家网上爬取租房数据并进行数据分析