美文网首页NetRx系列android网络开发
Retrofit分析-漂亮的解耦套路

Retrofit分析-漂亮的解耦套路

作者: stay4it | 来源:发表于2016-04-07 15:51 被阅读48633次

没耐心自己分析源码的同学,还可以参考Stay录制的视频版
Retrofit分析-漂亮的解耦套路(视频版)

万万没想到Retrofit会这么火,在没看源码之前,我简单的认为是因为它跟OkHttp同出一源(Square),所以才会炒的那么热。又或者是因为它能支持RxJava,所以火上浇油,一发不可收拾。

后来看过Retrofit源码之后,我才理解为什么它倍受关注,是因为它集诸优点于一身,并且炒鸡解耦。你能预见的特殊需求,都能非常容易的扩展。

没有HTTP框架的日子

我们先来看一下没有HTTP框架以前,我们是如何做请求的。


retrofit00.png
  1. 首先build request参数
  2. 因为不能在主线程请求HTTP,所以你得有个Executer或者线程
  3. enqueue后,通过线程去run你的请求
  4. 得到服务器数据后,callback回调给你的上层。

大概是以上4大步骤,在没有框架的年代,想要做一次请求,是万分痛苦的,你需要自己管理线程切换,需要自己解析读取数据,解析数据成对象,切换回主线程,回调给上层。

这段空白的时间持续了很久。从我10年工作起到12年,因为写烦了重复的代码,所以就得想办法,把那些变化的地方封装起来,也只是简单的封装。好在官方出了AsyncTask,虽然坑很多,但如果再自己维护一个队列,基本不会出现问题。更好的地方是数据格式从xml变成json了。gson解放了双手,再也不用解析dom了。

早些时期的HTTP框架

后来慢慢出了不少真正的HTTP框架。Stay也借鉴了很多文章,封装了一套适用于自身业务需求的框架。

这个时期的框架有个特点,就是拼了命去支持所有类型。比方说Volley支持直接返回Bitmap。xUtils不仅大而全,而且连多线程下载也要支持。在资源匮乏的时代,它们的存在有它们的道理。但如果说现在还用Volley做图片请求,还在用xUtils或Afinal里的各个模块。那就说不过去了。术业有专攻,百家争鸣的时期,难道不该选择最好的那一个吗?(Stay没真的用过xUtils和Afinal这种组合框架,潜意识告诉我,它们有毒,一旦某个环节出问题或者需要扩展,那代价就太大了)

Retrofit

好吧,介绍完HTTP框架的发展,让我们单纯的说说Retrofit吧。

tips:本文以retrofit最新版本2.0.1为例,大家也可以去github下源码,找tag为'parent-2.0.1'就可以。目前代码变动比较大。2.0.1已经使用okhttp3了,而我项目中2.0.0-beta2还是okhttp2.5。

retrofit的最大特点就是解耦,要解耦就需要大量的设计模式,假如一点设计模式都不懂的人,可能很难看懂retrofit。

先来看一张Stay画的精简流程图(如有错误,请斧正),类图就不画了。

retrofit01.png

Stay在一些设计模式很明确的地方做了标记。

外观模式,动态代理,策略模式,观察者模式。当然还有Builder模式,工厂等这些简单的我就没标。

先简述下流程吧:

  1. 通过门面Retrofit来build一个Service Interface的proxy

    retrofit03.png
  2. 当你调用这个Service Interface中的某个请求方法,会被proxy拦截。 retrofit02.png
  3. 通过ServiceMethod来解析invoke的那个方法 ,通过解析注解,传参,将它们封装成我们所熟悉的request。然后通过具体的返回值类型,让之前配置的工厂生成具体的CallAdapterResponseConverter,这俩我们稍后再解释。

  4. new一个OkHttpCall,这个OkHttpCall算是OkHttp的包装类,用它跟OkHttp对接,所有OkHttp需要的参数都可以看这个类。当然也还是可以扩展一个新的Call的,比如HttpUrlConnectionCall。但是有点耦合。看下图标注:


    retrofit031.png

    红框中显式的指明了OkHttpCall,而不是通过工厂来生成Call。所以如果你不想改源码,重新编译,那你就只能使用OkHttp了。不过这不碍事。(可能也是因为还在持续更新中,所以这块可能后面会改进的)

  5. 生成的CallAdapter有四个工厂,分别对应不同的平台,RxJava, Java8, Guava还有一个Retrofit默认的。这个CallAdapter不太好用中文解释。简单来说就是用来将Call转成T的一个策略。因为这里具体请求是耗时操作,所以你需要CallAdapter去管理线程。怎么管理,继续往下看。

  6. 比如RxJava会根据调用方法的返回值,如Response<'T> |Result<'T>|Observable<'T> ,生成不同的CallAdapter。实际上就是对RxJava的回调方式做封装。比如将response再拆解为success和error等。(这块还是需要在了解RxJava的基础上去理解,以后有时间可以再详细做分析)

  7. 在步骤5中,我们说CallAdapter还管理线程。比方说RxJava,我们知道,它最大的优点可以指定方法在什么线程下执行。如图

    retrofit04.png
    我们在子线程订阅(subscribeOn),在主线程观察(observeOn)。具体它是如何做的呢。我们看下源码。 retrofit05.png
    在adapt Call时,subscribeOn了,所以就切换到子线程中了。
  8. 在adapt Call中,具体的调用了Call execute(),execute()是同步的,enqueue()是异步的。因为RxJava已经切换了线程,所以这里用同步方法execute()。

    retrofit06.png
  9. 接下来的具体请求,就是OkHttp的事情了,retrofit要做成的就是等待返回值。在步骤4中,我们说OkHttpCall是OkHttp的包装类,所以将OkHttp的response转换成我们要的T,也是在OkHttpCall中执行的。

  10. 当然具体的解析转换操作也不是OkHttpCall来做的,因为它也不知道数据格式是什么样的。所以它只是将response包装成retrofit标准下的response。

  11. Converter->ResponseConverter,很明显,它是数据转换器。它将response转换成我们具体想要的T。Retrofit提供了很多converter factory。比如Gson,Jackson,xml,protobuff等等。你需要什么,就配置什么工厂。在Service方法上声明泛型具体类型就可以了。

  12. 最后,通过声明的observeOn线程回调给上层。这样上层就拿到了最终结果。至于结果再如何处理,那就是上层的事了。

再来回顾下Stay画的流程图:

retrofit01.png

这真是漫长的旅行,Stay也是debug一个个单步调试才梳理出来的流程。当然其中还有很多巧妙的解耦方式,我这里就不赘述了。大家可以看看源码分析下,当真是设计模式的经典示例。

我想现在大家应该对retrofit有所了解了。当你再给别人介绍retrofit的时候,就别只说它的注解方式多新颖,多炫技了。注解式框架有很多的,像j2ee中一大把。所以注解算不得多精湛的技艺。最牛逼的还是它的解耦方式,这个套路没有多年的实际架构经验是设计不出来的。

扩展阅读:

OkHttp, Retrofit, Volley应该选择哪一个?

Retrofit分析-谜之槽点

这么多开源框架,该用哪个好?

Retrofit分析-漂亮的解耦套路(视频版)

Retrofit分析-经典设计模式案例

相关文章

  • Retrofit 2.4.0 工作流程源码解析

    本文参考 Retrofit分析-漂亮的解耦套路图片来源 Retrofit分析-漂亮的解耦套路源码版本:Retrof...

  • Retrofit分析-漂亮的解耦套路

    没耐心自己分析源码的同学,还可以参考Stay录制的视频版 Retrofit分析-漂亮的解耦套路(视频版) 万万没想...

  • Retrofit分析-谜之槽点

    没耐心自己分析源码的同学,还可以参考Stay录制的视频版Retrofit分析-漂亮的解耦套路(视频版) 情况是这样...

  • Retrofit分析-漂亮的解耦套路

    没耐心自己分析源码的同学,还可以参考Stay录制的视频版Retrofit分析-漂亮的解耦套路(视频版) 万万没想到...

  • 读书笔记-2019-01-31

    Retrofit分析-漂亮的解耦套路 - 简书 『看完脑醒』考研的成本和风险,梦想要有但请先谈利弊!_哔哩哔哩 (...

  • 解耦的常用套路

    通常我们在网上找的第三方开源lib(好比高层模块),我们自己实现的部分好比底层模块,我们通过gradler的方式引...

  • 解耦的套路,核心的代理——手撸Retrofit核动力

    Retrofit用到的设计模式 解释Retrofit 解释ServiceMethod 解释converterFac...

  • 解耦

    解耦 对于大型重构, 最有效的手段就是 解耦, 解耦的目的使实现代码高聚合、松耦合。 解耦为何如此...

  • (MVP+RxJava+Retrofit)解耦+Mockito

    前言 首先,对于MVP、RxJava还不了解的同学,请先阅读这几篇文章: Android MVP模式 简单易懂的介...

  • Retrofit源码解析

    Retrofit是一套基于okhttp来封装的网络框架,它的意义在于将okhttp的使用变得更简洁更解耦,其作者J...

网友评论

  • 小默森:厉害
  • alin_lin:文章总结的简单,清晰
  • 阳诚海:知乎搬运工!
  • 998bd9557ae7:retrofit为啥要用注解,用注解有啥好处?
    SuperLino:通过注解可以在一个类里面配置每一个api请求的参数,方便管理。
    请求的时候另外通过动态代理,就可以把代理生成每一个请求,免去每次请求时构建网络请求参数等重复相关代码了。
  • ebf9089931f8:nice,写的非常好
  • cCT1zK:po主怎么debug看源码的?
  • e057f9ea83c1:要是能把Call对象和具体的某一个retrofit解耦就更好了。个人觉得把Call里面的enqueue方法去掉更好,改成一个具体的retrofit.enqueue(call)的方式, Call的创建不依赖于retrofit对象
  • gzfgeh:大神,看到 ServiceMethod serviceMethod = loadServiceMethod(method); 进去发现是缓存了ServiceMethod对象,但是为什么用LinkedHashMap而不用HashMap缓存呢,我知道LinkedHashMap能实现LRU缓存方式,但是这里没有用到啊,不明白这里用LinkedHashMap的用途,望大神告知,谢谢!
    stay4it:@gzfgeh 这个问题反着推,假设这里用LinkedHashMap要比HashMap好,那么好在哪里呢?这里只用到了get()与put()。单独比较这俩,LinkedHashMap多了链表,多了顺序,用它来存储ServiceMethod有什么好处呢?new LinkedHashMap时用的无参构造方法,保留了插入顺序,这样的好处是什么?这是个开放式问题,要我说原因我也不好说,所以就把分析过程列下来,至于真正的原因,要你自己判断了。
  • 8130566994ef:关于Retrofit的Config 哪一部分用了外观模式? :-) 。 不是建造者么
    chenxuxu:对外操作都封装在 retrofit 类中,stay 应该是指这点用到了【外观模式】。当然,这里也用了建造者模式。
  • George吴逸云:@stay4it可以转载吗?写好好
    stay4it:@吴逸云 可以的 注明出处就好
  • alex_wsc:博主视频中的代码,可否发一下?你有博客么?
  • jzhu085:请问下,最近也在学习rxjava+retrofit2 ,配合了rxjava,我应该怎么取消请求呢?以前是call.cancel,如果只是unsbscribe能取消么?
    hjhjw1991:@stay4it 回复竟然不能点赞, 授人以渔, 手动点赞
    stay4it:@老实巴交的读书人 当自己有疑问是,要尝试着自己找答案,retrofit2和rxjava产生耦合的地方就是RxJavaCallAdapterFactory。为什么不进去看下呢: )
  • f04552001e34:那个observeOn是用来切换线程的用途吧,可以调用多次。然后subscribeOn一般只调用一次。。。。,指定observable,不知道我这样理解对不对? :smile:
  • yzytmac:作者写的很好顺便问下studio左边代码缩进的竖线怎么修改颜色啊?
    stay4it:@雨小七 搜下android studio主题就好
  • Cliper:一直处于使用retrofit,API的阶段花了几个小时把视频看完的,看懂了。在结合stay的文章,讲真,真的很棒.......受益匪浅,爱你么么哒,老司机开车又快又稳!!!
    stay4it:@dreamLuo :smile:看过都说好。
  • 带心情去旅行:能将源码画成流程图,看来作者对Retrofit的了解已经到了一个境界,果然是android的老司机。什么时候飙车,带上我!!!
  • 3c669fc47b22:楼主,你好,感谢你的文章,我还有一点疑问,不知道你是怎么配置 Retrofit的,一般情况下使用addCallAdapterFactory(RxJavaCallAdapterFactory.create())的话,第7步中scheduler应该为null的,根据
    if (scheduler != null) {
    return observable.subscribeOn(scheduler);
    }
    应该是不会去执行observable.subscribeOn();所以也就不存在切换线程了,所以我觉得如果不是以createWithScheduler()生成RxJavaCallAdapterFactory时,真正的切换线程应该是调用接口方法时依靠的Rxjava指定。
    stay4it:@ChuckChen 是的,没错,我在第7点表明的是不那么准确,切换线程确实是在外部调用的。在第8点中call.execute()说明okhttp的调用是同步的,那切换线程也只能由外层来操作了。你理解的也很深刻哈。说CallAdapter还提供切换线程的方法会不会好一点?也只是rxjava把线程切换提供给外层。其他的calladapter都是内部处理好了。这也是为什么现在大家爱用rxjava+retrofit :)
    3c669fc47b22:@stay4it 嗯,谢谢,我说的是如果addCallAdapterFactory(RxJavaAdapterFactory.create())了,也就不存在会去取默认提供的callAdapter而是会根据需要返回的类型得到ResultCallAdapter,ResponseCallAdapter,SimpleCallAdapter中的一个,那么其实我们在adapt的时候只是获得了一个Observable,并没有执行切换线程的操作,此时切换线程应该是我们自己控制的。
    stay4it:@ChuckChen 对啊,如果你不配置rxjava的calladapter,它会提供默认的CallAdapter->ExecutorCallAdapter,这个在android上是通过handler来切换线程的,这个时候你得自己写Call.enqueue()或者自己起一个线程去执行。仔细看下流程图,或者可以看看我录制的视频。
  • 99a3e443b0b3:好东西,谢谢分享
  • 1e592c21f6de:看视频是stay最大的支持:smile:
    stay4it:@imxilife 没错没错,花了三周才弄出来的,认真看完保证能完全弄懂retrofit
  • shenmeguia:我还在用okhttp和xUtil怎么办,能不能教一下怎么用Retrofit
    stay4it:@Jorble 我录了视频课程,就在文章顶部,为什么不看一下呢
  • 2235fb3c7973:唉!没看懂。
    stay4it:@软件小宋 可以看我刚录的retrofit视频,不过看再多还得自己动手。视频地址在文章顶部。
  • c4600b33469e:思路很清晰,期待视频
  • 04da40e51179:赞一个
  • Smile_everyday:期待大神能视频带我们一起断点解析,谢谢LZ的辛苦分享。支持一个。
    stay4it:@android_wb hi,视频版retrofit已出,链接在文章顶部
  • YoKey::+1: 老司机开车~细读了一遍 用心之作~ :smile:
  • dea579f8285e:Stay,一直在关注你的文章和网站 希望能录个视频 。 :+1:
    stay4it:@独领风骚 hi,视频版retrofit已出,链接在文章顶部,不妨看看
    stay4it:@独领风骚 感谢关注,我尽力:smile:
  • 午空:先赞一个
  • 87f826a8000a:讲真。。。

    作为Android新手真的看不懂。。。
    stay4it:@Joffrey 讲真,如果看懂了说明java基础非常棒了
  • 小菜鸟程序媛:请问一下你的文章中的图是用什么软件画的
    小菜鸟程序媛:@stay4it thank you
    stay4it:@尺锤 gliffy, chrome上有插件的
  • Typer:正搞不懂calladapter和convert factory,这篇文章来的太及时了
    stay4it:@Typer hi,视频版retrofit已出,链接在文章顶部,不妨看看
    stay4it:@Typer 谢谢,我这也是硬翻,表达的还是不够清楚
  • 尸情化异:http://www.jianshu.com/p/69a3aff6bfac我也写了一篇,不知道有没有错,希望大神指正下
  • 661f7d1196eb:膜拜老司机~~~~
    老司机开车就是稳啊!!!!
  • ac2c0732fd94:po主几年经验了。
    stay4it:@Wing_Li 额,是2010年开始做。不是android做了10年。。。。
    Wing_Li:@stay4it 我去
    stay4it:@野生ChaoS 10年做android到现在。
  • 耳_总:老司机,不错
  • 189af35c2d2b:关于解耦,蒙圈中,功力不够,还需修炼啊
    stay4it:@小学生搞安卓 hi,视频版retrofit已出,链接在文章顶部,不妨看看
  • Ken_mmm:滴,学生卡,老司机快走
  • locatwang:抽时间看看先

本文标题:Retrofit分析-漂亮的解耦套路

本文链接:https://www.haomeiwen.com/subject/xkomlttx.html