关于Retrofit是啥,这里就不多解释了,还是先来瞅下官网:
![](https://img-blog.csdnimg.cn/img_convert/904742db94aff5df27bb445bdfa8554d.png)
而这次主要是了解它的底层动作机制,而在了解底层之前先来回顾一下官网的整体使用步骤:
![](https://img-blog.csdnimg.cn/img_convert/f2c637001ee7878bb36da16e8cb1eed0.png)
咱们也以官网的这个例子为例,先从简单的使用开始逐步深入,先新建一个工程:
![](https://img-blog.csdnimg.cn/img_convert/870a1ccec64ae72baa416d17e8c1cc5d.png)
然后增加retrofit的build引用 ,如下:
![](https://img-blog.csdnimg.cn/img_convert/9f55e95c5517acf2dc270be71c3c11aa.png)
然后按官网的步骤,首先创建一个API接口,如下:
![](https://img-blog.csdnimg.cn/img_convert/225a7ff3727ce744b368098acd9596db.png)
咱们以获取用户在github中的仓库为例,定义接口的API方法如下:
![](https://img-blog.csdnimg.cn/img_convert/3543861f3e6916aae830004aae045710.png)
然后具体来调用一下,也如官网的描述一样:
![](https://img-blog.csdnimg.cn/img_convert/ca06cbd4f49b177e773b160a3b82d7a2.png)
然后此时并未发起HTTP请求,需要像okhttp那样调用一下这个方法,分同步和异步,当然这里得用异步喽,如下:
![](https://img-blog.csdnimg.cn/img_convert/d2fc2344fc5de7d110cdab05a4626706.png)
然后增加访问网络的权限:
![](https://img-blog.csdnimg.cn/img_convert/f475d958a18116df072b6b7c3554228f.png)
先来查看一下我的github的仓库:
![](https://img-blog.csdnimg.cn/img_convert/6c6d9de186e79f2180b6d2e4918a412b.png)
![](https://img-blog.csdnimg.cn/img_convert/983c736bc2daa0506577548c1a11839c.png)
然后运行一下:
![](https://img-blog.csdnimg.cn/img_convert/cb47881138a669a2af8b1601210d6860.png)
成功了,其实这个接口返回的格式就是json,用浏览器可以访问看下结果:
![](https://img-blog.csdnimg.cn/img_convert/854d863d418dfc990016c9069b33ba1d.png)
接下来咱们将结果打印成我们看到的JSON格式一样,而咱们目前成功返回的是一个RsponseBody对像,它是来自okhttp的,如下:
![](https://img-blog.csdnimg.cn/img_convert/b87cb6a3e2f5231b6b2f148a018ae80b.png)
![](https://img-blog.csdnimg.cn/img_convert/5ff37a73e99a00666ce683ba2ae39e87.png)
此时就需要注册一个转换器了,这里不细讲怎么用的,直接上结果,重点是通过简单的使用掌握其深层次的本质原理,也就是源码分析,下面来看怎么做这个转换:
![](https://img-blog.csdnimg.cn/img_convert/3b0a95697784e1b3079120e292738530.png)
那此时怎么写这个转换工厂呢,这时需要再加一个库,也就是gson的支持,关于gson是啥就里就不多说了,直接添加依赖如下:
![](https://img-blog.csdnimg.cn/img_convert/b53ee1fee27a29097d1bae6d626f3de7.png)
此时就可以这么用了:
![](https://img-blog.csdnimg.cn/img_convert/0c3963eb866b045d51f81bef26453248.png)
接下来则需要修改API接口了,因为我们不想看到返回的ResonseBody对象,而想看到具体的JSON,从网站上返回的JSON可以看出其实就是一个JSON数组,所以返回的内容应该是一个List,所以修改一下:
![](https://img-blog.csdnimg.cn/img_convert/a159cce34ac66794bd658fdd0588d460.png)
然后里面的每个对象则需要我们手动定义出来,先假设这个对像类为Repo,如下:
![](https://img-blog.csdnimg.cn/img_convert/8c06eb2088f02dd13b97b946c3c38f61.png)
接下来则定义该类:
![](https://img-blog.csdnimg.cn/img_convert/5976049959b27db0f77799847bd11f0d.png)
然后再定义里面的字段,这里可以通过JSON自动转成Java的字段,可以用JsonFormat工具,如下:
![](https://img-blog.csdnimg.cn/img_convert/3be2890b10581f1cf1980606275e6dd7.png)
然后将Json数组中的对象内容拷至其中:
![](https://img-blog.csdnimg.cn/img_convert/bae8c54e4a1d59416a536d995c5dfd34.png)
![](https://img-blog.csdnimg.cn/img_convert/fecfb0e211a00e6c15e1152363dec81c.png)
接下来咱们来修改一下返回值,如下:
![](https://img-blog.csdnimg.cn/img_convert/b7274b7e523bf81d78e0cb7b633746c5.png)
然后运行:
![](https://img-blog.csdnimg.cn/img_convert/3c5679fb7408ab6a6573033c415cb35e.png)
ok,对于retrofit的简单用法就到此结束,重点是接下来分析它的源码:先从使用入口来进行分析的突破口,而使用入口就是它:
![](https://img-blog.csdnimg.cn/img_convert/7f7481e7f44e58313379131b1b871522.png)
能把它分析明白了,那对于retrofit的核心原理也就清楚啦,所以点进去看下它的源码:
![](https://img-blog.csdnimg.cn/img_convert/481b2bdd78981342893d8eafc86be255.png)
那此时就得看调用这个方法的对象是哪个了,如下:
![](https://img-blog.csdnimg.cn/img_convert/bfe43aa94b39935a3dffc36b1b5f08e2.png)
而这个API是咱们定义的接口,也是抽象的。。
![](https://img-blog.csdnimg.cn/img_convert/4a6a055c6ff44c1682dbe058be4f5b56.png)
那此时就再得往前追溯了,得看它具体的对象:
![](https://img-blog.csdnimg.cn/img_convert/5d48b39dea252216390fb7e794a3530b.png)
如果知道了gitHubService的具体对象那么最终我们就可以分析enqueue的具体实现了,所以定位其实现瞅一下:
![](https://img-blog.csdnimg.cn/img_convert/18c5ea086596a364f38bfe58dbe32d7c.png)
这个方法是retrofit的核心,其实可以看到有动态代理的东东,所以现在就集中来分析一下该实现:
![](https://img-blog.csdnimg.cn/img_convert/aacddd85f675ee21fcb7f9ef5601f559.png)
从字面意思来看是验证服务接口,看下究竟看了啥:
![](https://img-blog.csdnimg.cn/img_convert/b10b8c540f4912fe84090124524ee690.png)
不重要,继续往下读:
![](https://img-blog.csdnimg.cn/img_convert/74816a5022dfad0d445670a131fe8a8c.png)
这里是一个配置项的检查,表示是否要进行激进化的方法检查,具体就不细看了,不是核心,主要是对我们写的api的方法合法性的检查,如:
![](https://img-blog.csdnimg.cn/img_convert/18dd3c81d568ab2c9a1d6b062b61fa07.png)
如果开启了则会GitHubService一创建就会把所有的验证都做完了,很利于我们的调试,很早就可以发现代码写得不对,但是!!不利于性能,大致知道就行了,继续往下看:
![](https://img-blog.csdnimg.cn/img_convert/66cb5448b299a350d335a9cdba6a7178.png)
动态代理嘛,难道说retrofit的核心机制就是动态代理?其实确实是它,不过目前还不得而知,关于动态代理是啥这里就不过多解释了,j2se的基础,这里用伪代码来揭露其动态代码的本质,首先看第二个参数:
![](https://img-blog.csdnimg.cn/img_convert/4e2b5f10fd1b0020f52f2d1b48b31989.png)
其实动态代理就是首先生成一个实现了该接口的对象,伪代码表示一下:
![](https://img-blog.csdnimg.cn/img_convert/199bbc978b00642ba80374e659608d77.png)
然后动态代理不是还有第三个参数InvocationHandler么?如下:
![](https://img-blog.csdnimg.cn/img_convert/275e5733ef66fb1fb184666362f4c0ce.png)
其实它就会传到动态生成的代理对象里面,然后在每个具体方法实现中则会用到它来生成,伪代码如下:
![](https://img-blog.csdnimg.cn/img_convert/6f84915fae036bf11809504af939db4c.png)
如果说我们在API接口中定义了多个方法,则在这个动态生成的对象中的实现也都是用invocationHandler来实现的,这就是动态代理的本质。
那接下来就把精力花在这个invoke方法的具体实现上了,只要分析清楚了它,那么就知道为啥我们仅仅声明一个API接口retrofit就可以实现一个网络请求了,所以,研究一下invoke方法的具体实现:
![](https://img-blog.csdnimg.cn/img_convert/68e1438b367405c1f575df944fbb7faa.png)
![](https://img-blog.csdnimg.cn/img_convert/2569687b4adff2ed48cb8ebf001826bf.png)
![](https://img-blog.csdnimg.cn/img_convert/49402ba744f851248b244d4a0a084192.png)
而如果调用的是接口中的默认实现方法【这是Java8才有的】,直接也不做其它任何处理了,对于使用retrofit而言不可能有这种默认方法,所以可以略过这个判断细节,继续往下探究:
![](https://img-blog.csdnimg.cn/img_convert/ba81c5fb295d17cf99654b78d2a9f23c.png)
好晕呀,这三行中涉及到完全陌生的ServiceMethod、OkHttpCall,完全不明白,这里就涉及到一个读源码的小技巧了,对于都看不懂的情况下,先对涉及到的类都大至认识一下既可,不用深究,所以咱们一个个先来大致瞅一下:
![](https://img-blog.csdnimg.cn/img_convert/0aed10e4c500a2fcb8bb7a20d546ce2f.png)
啥意思?首先得理解一下什么是adapter,这个在我们listview的开发中必用的概念,还是先看一下它词的本义:
![](https://img-blog.csdnimg.cn/img_convert/2cd3849a3e617dd023a46796dd241da0.png)
也就是做转接用的,也就是可以猜测ServiceMethod的作用是:
![](https://img-blog.csdnimg.cn/img_convert/d82cba27b54edda1cbb40a2fa52a9cae.png)
然后此类的代码量太大,也没法继续往下看了,还是返回到主调代码处继续了解其它的东东,继续看下它:
![](https://img-blog.csdnimg.cn/img_convert/2d65a9767df37e5b7460e69d1c0082bc.png)
然后咱们来看一下ServiceMethod是如何生成的,通过生成细节看是否能进对ServiceMethod有一个进一步的了解,如下:
![](https://img-blog.csdnimg.cn/img_convert/bdfee28d80909c491e8510f7c9aad618.png)
![](https://img-blog.csdnimg.cn/img_convert/dbc95327f0f3c2f0ab0a7a491a3f8b64.png)
然后再看一下build()方法的细节:
![](https://img-blog.csdnimg.cn/img_convert/a1def2288ec762c4153ecca8e900fb98.png)
然后再通过构造来实例化:
![](https://img-blog.csdnimg.cn/img_convert/b92b6298298b56c9a011df13d8c0b9f1.png)
很经典的Builder模式,不过整个构建对象的细节完全看不懂,先暂且放着,等回过头按需再来查看,先来说一下Builder模式,人人皆知,这里简单说一下它的好处,通常我们用Builder模式通常会这样写:
![](https://img-blog.csdnimg.cn/img_convert/8d40dd9909922c304f8136f62491ddaf.png)
那它有啥好处呢?对于Person中有字段是有初始化成本的,什么意思?比如我们用正常的方式来初始化会这样写:
![](https://img-blog.csdnimg.cn/img_convert/618af7b03ade01c5bca12f1e78bc539f.png)
首先就在内存中有person对象了,接着再来修改一下性别:
![](https://img-blog.csdnimg.cn/img_convert/b7856d6dffed24d11fee82498a68f595.png)
而默认性别是女的,此句执行之后就需要在内存中将女姓给擦掉,然后用这个设置的男性来替代,这是有性能损耗的,接着再来修改年龄:
![](https://img-blog.csdnimg.cn/img_convert/10246af3d991b2248d224e0b3176765e.png)
如果默认年龄是24,那此时内存中又得将24给擦掉然后再画一个31岁的人,再接下来:
![](https://img-blog.csdnimg.cn/img_convert/3cf31fa2e30cc945a184c2a4a6ef967a.png)
默认人是走路的行为,此时又得内存进行擦除改掉用户的行为,所以说这种传统的方式是有性能损耗的,而Builder模式则在构建对象时没有提前生成内存,先生成一个配置清单,最终一起来构建对象,这是它的最大好处之一,另外一个好处就是当参数较多的时候这样写层次也比较清晰,关于builder模式这里简单提一下,还得回到咱们所关心的retrofit实现原理上来:
![](https://img-blog.csdnimg.cn/img_convert/ea93677fef1d7677488b1c487cbaf4cd.png)
打开瞅下它是啥?
![](https://img-blog.csdnimg.cn/img_convert/bd5193fddd41d4e05ceb62677fc06291.png)
![](https://img-blog.csdnimg.cn/img_convert/0d1a3c82bf976245d1930723f7dd1ecf.png)
那不就是说:
![](https://img-blog.csdnimg.cn/img_convert/ccdf893e85a7481573a1b0b277ab7734.png)
所以此时咱们可以看一下enqueue的具体实现:
![](https://img-blog.csdnimg.cn/img_convert/f6b4bc76025dbdf7922ab320cc6ae9f8.png)
先跳出这个实现细节,总的来回顾一下:
![](https://img-blog.csdnimg.cn/img_convert/6caa02782b410de6d2c3a7e3217654b2.png)
所以点进入再看最后一行的细节:
![](https://img-blog.csdnimg.cn/img_convert/4ca1c3fc02a238fae0519547240c49ee.png)
没办法,还得硬着头皮点进去瞅下:
![](https://img-blog.csdnimg.cn/img_convert/c8e0b357058e2e797401a48877312d6c.png)
那看不懂呀,怎么整,目前我们要了解的这三行代码,前两行大致猜到了一些意思,而最后一行完全不晓得其内部的细节,那接下来就从头来细看一下,看是否通过细看能发现一些线索:
![](https://img-blog.csdnimg.cn/img_convert/f7c0058c8e7eaf12eb6a10871499ed0f.png)
这个之前稍加看过,里在就是维护了一个缓存,不过这里还是要看一下ServiceMethod的创建过程:
![](https://img-blog.csdnimg.cn/img_convert/c15005f4b1773365f6a239124cc80346.png)
![](https://img-blog.csdnimg.cn/img_convert/8822e6ea07a2e39d5d464928bcf3428e.png)
其中第一句看到了一个之前的疑问:
![](https://img-blog.csdnimg.cn/img_convert/8ba5906de8a740fd2d71bb5337b9e171.png)
![](https://img-blog.csdnimg.cn/img_convert/4260cb094ec61d30c576100de03230fb.png)
其中这上callAdapter是一个接口,所以此时不就解惑了么,所以看一下callAdapter是如何创建的?
![](https://img-blog.csdnimg.cn/img_convert/f32c7ea17d19c50739fb8884e97279a3.png)
![](https://img-blog.csdnimg.cn/img_convert/4d48e3e549bdd2bccf34b92fa5c16723.png)
跟进去:
![](https://img-blog.csdnimg.cn/img_convert/a6667946045f971165b14083028e8429.png)
再往下跟:
![](https://img-blog.csdnimg.cn/img_convert/1c4fe99918fe717087f9a9d5e14ee7df.png)
接下来就得看一下这段代码的实现了,先来瞅一下callAdapterFactories对象:
![](https://img-blog.csdnimg.cn/img_convert/b772cc30c47c09bf3ab2fc138a07478d.png)
所以看一下它的调用,其实就是在build()方法中,如我们在Activity写的:
![](https://img-blog.csdnimg.cn/img_convert/afa9c776d9175cb349c801f443bcf0fa.png)
![](https://img-blog.csdnimg.cn/img_convert/003fc1bc25a6f7c5eb47b98f8a5222dc.png)
所以此时再看一下callAdapterFactories的创建来源:
![](https://img-blog.csdnimg.cn/img_convert/de425dbd51647fbc2e794461430dbaf6.png)
![](https://img-blog.csdnimg.cn/img_convert/20259fd5595120b8f651c775c099adcc.png)
然后就得看下一句了:
![](https://img-blog.csdnimg.cn/img_convert/667365a789bc45291edf22c33713e71a.png)
所以。。得看一下"platform.defaultCallAdapterFactory(callbackExecutor)"的细节:
![](https://img-blog.csdnimg.cn/img_convert/42a96b7d77e6b1e63119797be2c58847.png)
![](https://img-blog.csdnimg.cn/img_convert/2c74618e8a92957f7dce50e4c16ea09f.png)
如:
![](https://img-blog.csdnimg.cn/img_convert/6c83e448fbf7aede8189f72f7bf04fdb.png)
其中我们可以看到其实现中用到了一个“callbackExecutor”,通过它的执行然后再处理的回调:
![](https://img-blog.csdnimg.cn/img_convert/3477ef36fb68a081ed7ca868e7b173ff.png)
所以得看一下callBackExecutor是如何传递进来的,此时就又得回调Retrofit.build()方法来了:
![](https://img-blog.csdnimg.cn/img_convert/347eff99f95ff74bd4e6aa06630ea935.png)
然后再进一步跟一下此callbackExecutor的创建细节:
![](https://img-blog.csdnimg.cn/img_convert/18e1e404a304bcfa8b0615cb897d6c1c.png)
![](https://img-blog.csdnimg.cn/img_convert/b21b4edfe27a79e87470e00d6807777a.png)
那。。原来我们看到的calladapter的作用是进行线程的转换哦,那我们继续回到ServiceMethod.build()方法分析:
![](https://img-blog.csdnimg.cn/img_convert/260610eadea9bda30ba6626d84b41fb7.png)
拿我们定义的API接口方法来说就是指的:
![](https://img-blog.csdnimg.cn/img_convert/ef738aa0987df8919984114ec70d83b1.png)
接下来往下:
![](https://img-blog.csdnimg.cn/img_convert/c2ddc18507b83b8e40559e70f4cc0f97.png)
![](https://img-blog.csdnimg.cn/img_convert/9f1e5947c6ab315886dc1f0344f0b1b9.png)
![](https://img-blog.csdnimg.cn/img_convert/3b4c64e7253fd63977db41af938bc85f.png)
继续往下
![](https://img-blog.csdnimg.cn/img_convert/892bc27b15380111872a7ac77b370c86.png)
![](https://img-blog.csdnimg.cn/img_convert/c243b4d2dca74762b371a97b96f8953a.png)
这不就是指么:
![](https://img-blog.csdnimg.cn/img_convert/dca76855bf77cc65007931606af9186c.png)
好,再继续往下:
![](https://img-blog.csdnimg.cn/img_convert/bb736a5a9727c0ae378dea85e3e8dbbd.png)
![](https://img-blog.csdnimg.cn/img_convert/263697941c53f7bbfacb35f354f5e828.png)
另外有一个细节需要注意retrofit会对我们写的注解的正确性做验证,会让我们更加规范的使用okhttp,比如multipart需要配合part来使用等,好对于ServiceMethod的build()方法可以发现其实就是对我们定义的API方法进行了解析并存下来,然后再实例化它:
![](https://img-blog.csdnimg.cn/img_convert/c43c87c8f2938430b21033036af4824e.png)
至此,咱们要想分析关键的第一句代码就彻底搞清楚其作用了,回顾一下:
![](https://img-blog.csdnimg.cn/img_convert/02bb2798e5f14bd8aa453d0de2c71cf8.png)
![](https://img-blog.csdnimg.cn/img_convert/c47e71311bcc93b5ee7307dd304ef9ed.png)
好,接下来再分析核心的第二句代码,比如好理解:
![](https://img-blog.csdnimg.cn/img_convert/31aaf29c3f8ccbd768496390375623bf.png)
![](https://img-blog.csdnimg.cn/img_convert/05ce33602a7a89c5eea71d05b49b8f77.png)
接着再来看第三句代码,其实通过上面的分析也晓得其作用了,挼一下:
![](https://img-blog.csdnimg.cn/img_convert/8d12ba43d5156ab288cc70e71dcb8f30.png)
![](https://img-blog.csdnimg.cn/img_convert/dec67930127ccc3d9c157de60cbd1c3e.png)
然后此时得回顾一下callAdpater是如何创建出来的:
![](https://img-blog.csdnimg.cn/img_convert/ff7eddef18a57ccc98c39dec634c4195.png)
![](https://img-blog.csdnimg.cn/img_convert/02ab61e32685cf4c21a32ce15fb201ea.png)
![](https://img-blog.csdnimg.cn/img_convert/62cde2c53138230cf94c7d0e9358b534.png)
![](https://img-blog.csdnimg.cn/img_convert/415e26b1957d904efd5c961c2c0607b2.png)
![](https://img-blog.csdnimg.cn/img_convert/5a22398a5c881e08b17d8325cce83d96.png)
然后此方法的调用是在调用build()时进行的,如下:
![](https://img-blog.csdnimg.cn/img_convert/0effd3ad47cb68fa24a9e83bebd18940.png)
![](https://img-blog.csdnimg.cn/img_convert/42dc88c8dbe07f744b80d58a6ee89ae8.png)
![](https://img-blog.csdnimg.cn/img_convert/d8e34e9af0eb1aefac56eadc597282f1.png)
![](https://img-blog.csdnimg.cn/img_convert/c88146dbb59c46471ef7c3102038894d.png)
所以最终调用adapt()方法的其实是ExecutorCallAdapterFactory里面的了,如下:
![](https://img-blog.csdnimg.cn/img_convert/a5ec5b4d83540b440109736a7e1c3476.png)
也就是最终retrofit动态生成的对像在调用它里面的getRepos()方法返回的是ExecutorCallbackCall对像,如下:
![](https://img-blog.csdnimg.cn/img_convert/251b85de9751f1616dcc3a6a1195617f.png)
所以接下来我们再来分析最初我们分析不动的方法就顺其自然啦,也就是:
![](https://img-blog.csdnimg.cn/img_convert/37bef04ed3ab5a87718e90a3edc0e140.png)
那就是直接调用ExecutorCallbackCall.enqueue()方法,如下:
![](https://img-blog.csdnimg.cn/img_convert/cdac9d71dac6cb1434a7e398c78b0eb9.png)
而代理的call是在我们代理对像方法执行时动态创建的,如下:
![](https://img-blog.csdnimg.cn/img_convert/b8b63d49738e920807a94f5eb88db6a4.png)
所以最终就会转到OkHttpCall.enqueue()方法来,如下:
![](https://img-blog.csdnimg.cn/img_convert/41a71d2d367d942d565763e94fdff34e.png)
![](https://img-blog.csdnimg.cn/img_convert/1b089c8e77b008a4d8a73ec5bf533e9d.png)
其中还是利用了ServiceMethod来对之前解析的东东来转换成了okhttp的call,如下:
![](https://img-blog.csdnimg.cn/img_convert/66deb3c00fb73de1f591d2d4ed30d0f4.png)
然后再利用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:
![](https://img-blog.csdnimg.cn/img_convert/a05e5152ce83b41d1de0d48be15946fd.png)
然后这个parseResponse()方法就可以体现出它与http的关系了,就是用了http的知识来编写的,大致瞅一下:
![](https://img-blog.csdnimg.cn/img_convert/7fcf6f8acaf59c01c1f2206f2edc5459.png)
其中从okhttp的reponse转成retrofit的response最终还用到了converter了,如下:
![](https://img-blog.csdnimg.cn/img_convert/4b799df977c9bfea3d4cad5a1548a44b.png)
![](https://img-blog.csdnimg.cn/img_convert/c415e22052a4365e2967db0df7c7aee2.png)
最后还有一个知识就是retrofit如何集成rxjava,首先得集成一下rxjava,如下:
![](https://img-blog.csdnimg.cn/img_convert/fa5aeb9785b8b1f09dda9ad2c86936a3.png)
然后此时需要在增加一个calladapter,如下:
![](https://img-blog.csdnimg.cn/img_convert/987970689090d9d272402800f32592f3.png)
此时我们的API定义返回就不用返回Call对像了,而是可以返回一个Observable,如下:
![](https://img-blog.csdnimg.cn/img_convert/004ed59ef98bcb918c4cf04816e4490d.png)
然后就可以用rxjava的那一套来进行接口请求及返回处理了,Retrofit是可以支持多个Adapter的,瞅一下:
![](https://img-blog.csdnimg.cn/img_convert/c23cadf022623a989c394d2050a0bfd1.png)
![](https://img-blog.csdnimg.cn/img_convert/0bdddf40039b361d70abcf3d1dea19a0.png)
其中我们知道Retrofit默认的Adapter为CallAdapter,是可以将ResponseBody转换成一个Call对象,如下:
![](https://img-blog.csdnimg.cn/img_convert/badee9091cee56e3dc3228412626edc7.png)
其具体实现是:
![](https://img-blog.csdnimg.cn/img_convert/c1a579a90a0d12961d9db607eb135b68.png)
并达到一个切换线程的作用。
而此时加了一个Rxjava的CallAdapter,如下:
![](https://img-blog.csdnimg.cn/img_convert/a8ffe35ead686c95d709ac8138c35823.png)
![](https://img-blog.csdnimg.cn/img_convert/0be6bae3cb8593fabf91cafc4fb47a86.png)
所以我们在api可以为:
![](https://img-blog.csdnimg.cn/img_convert/93dda6d7f421bd14fa63ab16abba6ac9.png)
到此!!已经完整将Retrofit的整个核心机制分析完了,对于之后在实际工作中用Retrofit也更加踏实了~~说实话还是挺复杂的。