关于Retrofit是啥,这里就不多解释了,还是先来瞅下官网:

而这次主要是了解它的底层动作机制,而在了解底层之前先来回顾一下官网的整体使用步骤:

咱们也以官网的这个例子为例,先从简单的使用开始逐步深入,先新建一个工程:

然后增加retrofit的build引用 ,如下:

然后按官网的步骤,首先创建一个API接口,如下:

咱们以获取用户在github中的仓库为例,定义接口的API方法如下:

然后具体来调用一下,也如官网的描述一样:

然后此时并未发起HTTP请求,需要像okhttp那样调用一下这个方法,分同步和异步,当然这里得用异步喽,如下:

然后增加访问网络的权限:

先来查看一下我的github的仓库:

然后运行一下:

成功了,其实这个接口返回的格式就是json,用浏览器可以访问看下结果:

接下来咱们将结果打印成我们看到的JSON格式一样,而咱们目前成功返回的是一个RsponseBody对像,它是来自okhttp的,如下:

此时就需要注册一个转换器了,这里不细讲怎么用的,直接上结果,重点是通过简单的使用掌握其深层次的本质原理,也就是源码分析,下面来看怎么做这个转换:

那此时怎么写这个转换工厂呢,这时需要再加一个库,也就是gson的支持,关于gson是啥就里就不多说了,直接添加依赖如下:

此时就可以这么用了:

接下来则需要修改API接口了,因为我们不想看到返回的ResonseBody对象,而想看到具体的JSON,从网站上返回的JSON可以看出其实就是一个JSON数组,所以返回的内容应该是一个List,所以修改一下:

然后里面的每个对象则需要我们手动定义出来,先假设这个对像类为Repo,如下:

接下来则定义该类:

然后再定义里面的字段,这里可以通过JSON自动转成Java的字段,可以用JsonFormat工具,如下:

然后将Json数组中的对象内容拷至其中:

接下来咱们来修改一下返回值,如下:

然后运行:

ok,对于retrofit的简单用法就到此结束,重点是接下来分析它的源码:先从使用入口来进行分析的突破口,而使用入口就是它:

能把它分析明白了,那对于retrofit的核心原理也就清楚啦,所以点进去看下它的源码:

那此时就得看调用这个方法的对象是哪个了,如下:

而这个API是咱们定义的接口,也是抽象的。。

那此时就再得往前追溯了,得看它具体的对象:

如果知道了gitHubService的具体对象那么最终我们就可以分析enqueue的具体实现了,所以定位其实现瞅一下:

这个方法是retrofit的核心,其实可以看到有动态代理的东东,所以现在就集中来分析一下该实现:

从字面意思来看是验证服务接口,看下究竟看了啥:

不重要,继续往下读:

这里是一个配置项的检查,表示是否要进行激进化的方法检查,具体就不细看了,不是核心,主要是对我们写的api的方法合法性的检查,如:

如果开启了则会GitHubService一创建就会把所有的验证都做完了,很利于我们的调试,很早就可以发现代码写得不对,但是!!不利于性能,大致知道就行了,继续往下看:

动态代理嘛,难道说retrofit的核心机制就是动态代理?其实确实是它,不过目前还不得而知,关于动态代理是啥这里就不过多解释了,j2se的基础,这里用伪代码来揭露其动态代码的本质,首先看第二个参数:

其实动态代理就是首先生成一个实现了该接口的对象,伪代码表示一下:

然后动态代理不是还有第三个参数InvocationHandler么?如下:

其实它就会传到动态生成的代理对象里面,然后在每个具体方法实现中则会用到它来生成,伪代码如下:

如果说我们在API接口中定义了多个方法,则在这个动态生成的对象中的实现也都是用invocationHandler来实现的,这就是动态代理的本质。

那接下来就把精力花在这个invoke方法的具体实现上了,只要分析清楚了它,那么就知道为啥我们仅仅声明一个API接口retrofit就可以实现一个网络请求了,所以,研究一下invoke方法的具体实现:

而如果调用的是接口中的默认实现方法【这是Java8才有的】,直接也不做其它任何处理了,对于使用retrofit而言不可能有这种默认方法,所以可以略过这个判断细节,继续往下探究:

好晕呀,这三行中涉及到完全陌生的ServiceMethod、OkHttpCall,完全不明白,这里就涉及到一个读源码的小技巧了,对于都看不懂的情况下,先对涉及到的类都大至认识一下既可,不用深究,所以咱们一个个先来大致瞅一下:

啥意思?首先得理解一下什么是adapter,这个在我们listview的开发中必用的概念,还是先看一下它词的本义:

也就是做转接用的,也就是可以猜测ServiceMethod的作用是:

然后此类的代码量太大,也没法继续往下看了,还是返回到主调代码处继续了解其它的东东,继续看下它:

然后咱们来看一下ServiceMethod是如何生成的,通过生成细节看是否能进对ServiceMethod有一个进一步的了解,如下:

然后再看一下build()方法的细节:

然后再通过构造来实例化:

很经典的Builder模式,不过整个构建对象的细节完全看不懂,先暂且放着,等回过头按需再来查看,先来说一下Builder模式,人人皆知,这里简单说一下它的好处,通常我们用Builder模式通常会这样写:

那它有啥好处呢?对于Person中有字段是有初始化成本的,什么意思?比如我们用正常的方式来初始化会这样写:

首先就在内存中有person对象了,接着再来修改一下性别:

而默认性别是女的,此句执行之后就需要在内存中将女姓给擦掉,然后用这个设置的男性来替代,这是有性能损耗的,接着再来修改年龄:

如果默认年龄是24,那此时内存中又得将24给擦掉然后再画一个31岁的人,再接下来:

默认人是走路的行为,此时又得内存进行擦除改掉用户的行为,所以说这种传统的方式是有性能损耗的,而Builder模式则在构建对象时没有提前生成内存,先生成一个配置清单,最终一起来构建对象,这是它的最大好处之一,另外一个好处就是当参数较多的时候这样写层次也比较清晰,关于builder模式这里简单提一下,还得回到咱们所关心的retrofit实现原理上来:

打开瞅下它是啥?

那不就是说:

所以此时咱们可以看一下enqueue的具体实现:

先跳出这个实现细节,总的来回顾一下:

所以点进入再看最后一行的细节:

没办法,还得硬着头皮点进去瞅下:

那看不懂呀,怎么整,目前我们要了解的这三行代码,前两行大致猜到了一些意思,而最后一行完全不晓得其内部的细节,那接下来就从头来细看一下,看是否通过细看能发现一些线索:

这个之前稍加看过,里在就是维护了一个缓存,不过这里还是要看一下ServiceMethod的创建过程:

其中第一句看到了一个之前的疑问:

其中这上callAdapter是一个接口,所以此时不就解惑了么,所以看一下callAdapter是如何创建的?

跟进去:

再往下跟:

接下来就得看一下这段代码的实现了,先来瞅一下callAdapterFactories对象:

所以看一下它的调用,其实就是在build()方法中,如我们在Activity写的:

所以此时再看一下callAdapterFactories的创建来源:

然后就得看下一句了:

所以。。得看一下"platform.defaultCallAdapterFactory(callbackExecutor)"的细节:

如:

其中我们可以看到其实现中用到了一个“callbackExecutor”,通过它的执行然后再处理的回调:

所以得看一下callBackExecutor是如何传递进来的,此时就又得回调Retrofit.build()方法来了:

然后再进一步跟一下此callbackExecutor的创建细节:

那。。原来我们看到的calladapter的作用是进行线程的转换哦,那我们继续回到ServiceMethod.build()方法分析:

拿我们定义的API接口方法来说就是指的:

接下来往下:

继续往下

这不就是指么:

好,再继续往下:

另外有一个细节需要注意retrofit会对我们写的注解的正确性做验证,会让我们更加规范的使用okhttp,比如multipart需要配合part来使用等,好对于ServiceMethod的build()方法可以发现其实就是对我们定义的API方法进行了解析并存下来,然后再实例化它:

至此,咱们要想分析关键的第一句代码就彻底搞清楚其作用了,回顾一下:

好,接下来再分析核心的第二句代码,比如好理解:

接着再来看第三句代码,其实通过上面的分析也晓得其作用了,挼一下:

然后此时得回顾一下callAdpater是如何创建出来的:

然后此方法的调用是在调用build()时进行的,如下:

所以最终调用adapt()方法的其实是ExecutorCallAdapterFactory里面的了,如下:

也就是最终retrofit动态生成的对像在调用它里面的getRepos()方法返回的是ExecutorCallbackCall对像,如下:

所以接下来我们再来分析最初我们分析不动的方法就顺其自然啦,也就是:

那就是直接调用ExecutorCallbackCall.enqueue()方法,如下:

而代理的call是在我们代理对像方法执行时动态创建的,如下:

所以最终就会转到OkHttpCall.enqueue()方法来,如下:

其中还是利用了ServiceMethod来对之前解析的东东来转换成了okhttp的call,如下:

然后再利用Okhttp的Call进行异步请求,如下:

@Override 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();}}});}

其中回调是先对OkHttp的Response进行解析,解析成Retrofit的Response:

然后这个parseResponse()方法就可以体现出它与http的关系了,就是用了http的知识来编写的,大致瞅一下:

其中从okhttp的reponse转成retrofit的response最终还用到了converter了,如下:

最后还有一个知识就是retrofit如何集成rxjava,首先得集成一下rxjava,如下:

然后此时需要在增加一个calladapter,如下:

此时我们的API定义返回就不用返回Call对像了,而是可以返回一个Observable,如下:

然后就可以用rxjava的那一套来进行接口请求及返回处理了,Retrofit是可以支持多个Adapter的,瞅一下:

其中我们知道Retrofit默认的Adapter为CallAdapter,是可以将ResponseBody转换成一个Call对象,如下:

其具体实现是:

并达到一个切换线程的作用。

而此时加了一个Rxjava的CallAdapter,如下:

所以我们在api可以为:

到此!!已经完整将Retrofit的整个核心机制分析完了,对于之后在实际工作中用Retrofit也更加踏实了~~说实话还是挺复杂的。

转载于:https://www.cnblogs.com/webor2006/p/10502230.html

从Retrofit的源码来看 HTTP相关推荐

  1. [动态代理三部曲:下] - 从动态代理,看Retrofit的源码实现

    前言 关于动态代理的系列文章,到此便进入了最后的"一出好戏".前俩篇内容分别展开了:从源码上,了解JDK实现动态代理的原理:以及从动态代理切入,学会看class文件结构的含义. 如 ...

  2. 别人家SDK的设计模式——Android Retrofit库源码解读

    作者:网易合作产品部·李若昆 我们在日常编写代码中免不了会用到各种各样第三方库,网络请求.图片加载.数据库等等.有些lib接入可能方便到几行代码搞定,有些lib可能从demo.文档到测试都是坑(比如l ...

  3. android基础复习笔记——5.从OkHttp的源码来看HTTP

    1.OkHttp的历史: 最初是square觉得android给的那一套方案不是很好用,于是他给做了一下包装,包装以后就好用了,慢慢地,他们把httpclient给剔除了,再后来,他被Google给收 ...

  4. Android 深入Http(4)从OkHttp源码来看Http,音视频开发工程师前景

    想必最重要的是哪几行,大家都知道了. Response response = getResponseWithInterceptorChain() 这行代码就突然Response了,这说明getResp ...

  5. 【Retrofit】Retrofit的源码解析

    Retrofit是一款优秀的开源框架.接下来从源码的角度深入了解Retrofit的优势. 执行流程 Retrofit使用动态代理,代理接口的方法,如果缓存了这个方法,直接使用.如果没有缓存,解析方法的 ...

  6. 【Android】Retrofit基础源码分析

    文章目录 流程图 基本使用 1. 创建服务端ApiInterface 2.配置BaseUrl生成Retrofit对象 3.生成服务端ApiInterface对象 4.调用服务端ApiInterface ...

  7. 闲聊AQS面试和源码解读---可重入锁、LockSupport、CAS;从ReentrantLock源码来看公平锁与非公平锁、AQS到底是怎么用CLH队列来排队的?

    AQS原理可谓是JUC面试中的重灾区之一,今天我们就来一起看看AQS到底是什么? 这里我先整理了一些JUC面试最常问的问题? 1.Synchronized 相关问题以及可重入锁 ReentrantLo ...

  8. Netty和JDK源码来看Netty的NIO和JDK的NIO有什么不同

    JDK底层提供了NIO实现,在Linux环境会调用内核epoll. 但是Netty通过JNI的方式提供了Native Socket Transport,为什么Netty要自己搞一套NIO呢? 这篇文章 ...

  9. Java并发——结合CountDownLatch源码、Semaphore源码及ReentrantLock源码来看AQS原理

    前言: 如果说J.U.C包下的核心是什么?那我想答案只有一个就是AQS.那么AQS是什么呢?接下来让我们一起揭开AQS的神秘面纱 AQS是什么? AQS是AbstractQueuedSynchroni ...

  10. 通过分析nginx upstream源码来看动态配置upstream模块

    upstream回源处理流程 代码围绕着ngx_http_upstream.c展开,该模块主要为创建mainconf函数: static void *ngx_http_upstream_create_ ...

最新文章

  1. 请教如何改善C#中socket通信机客户端程序的健壮性
  2. Linux总线驱动-02: struct bus_type 结构体
  3. [Phonegap+Sencha Touch] 移动开发18 Sencha Touch项目通过phonegap打包后的程序名字的问题...
  4. 2.4g和5g要不要合并_2.4 序列之字符串
  5. 寒假每日一题(入门组)【week1 完结】
  6. Redis的设计与实现之跳表
  7. 南明区将引进和培养大数据高端人才逾千名
  8. python123温度转换-python二级备考 day2
  9. 【前端统计图】echarts改变颜色属性的demo
  10. java readline 超时_跳过Java中的BufferedReader readLine()方法
  11. Python 学习编程 【for语句breakcontinue语句使用】(一)
  12. 大象起舞:用PostgreSQL解海盗分金问题
  13. hdu 2082 找单词(母函数)
  14. Windows Server 2008 将与 Visual Studio 2008 和 SQL Server 2008 于2008年2月27 日在洛杉矶共同发布...
  15. 计算机网络实验_专业介绍篇 | 计算机网络技术专业
  16. beautifulsoup_如何使用 Python 和 BeautifulSoup 爬取网站
  17. @SessionAttributes
  18. HDU - 3506 Monkey Party
  19. JDBC10 Blob二进制对象
  20. 服务器控制口协议,服务器管理ipmi接口协议的扩展方法 Extension Methods server management interface protocol ipmi...

热门文章

  1. 一个工作三年左右的Java程序员跟大家分享从业心得
  2. 这个时代,开发简单多了
  3. 0 基础转行 Android 工程师是种怎样的体验?
  4. 线程 -- ThreadLocal
  5. HDU1054 Strategic Game —— 最小点覆盖 or 树形DP
  6. dedecms 中变量函数
  7. poj 1743 Musical Theme【后缀自动机】
  8. not1,not2,bind1st,bind2nd
  9. 专线维护 07/11
  10. 声源测向: TDOA-GCC-PATH方法