Retrofit分析-漂亮的解耦套路

沒耐心自己分析源碼的同學(xué),還可以參考Stay錄制的視頻版
Retrofit分析-漂亮的解耦套路(視頻版)

萬萬沒想到Retrofit會(huì)這么火,在沒看源碼之前,我簡(jiǎn)單的認(rèn)為是因?yàn)樗鶲kHttp同出一源(Square),所以才會(huì)炒的那么熱。又或者是因?yàn)樗苤С諶xJava,所以火上澆油,一發(fā)不可收拾。

后來看過Retrofit源碼之后,我才理解為什么它倍受關(guān)注,是因?yàn)樗T優(yōu)點(diǎn)于一身,并且炒雞解耦。你能預(yù)見的特殊需求,都能非常容易的擴(kuò)展。

沒有HTTP框架的日子

我們先來看一下沒有HTTP框架以前,我們是如何做請(qǐng)求的。


retrofit00.png
  1. 首先build request參數(shù)
  2. 因?yàn)椴荒茉谥骶€程請(qǐng)求HTTP,所以你得有個(gè)Executer或者線程
  3. enqueue后,通過線程去run你的請(qǐng)求
  4. 得到服務(wù)器數(shù)據(jù)后,callback回調(diào)給你的上層。

大概是以上4大步驟,在沒有框架的年代,想要做一次請(qǐng)求,是萬分痛苦的,你需要自己管理線程切換,需要自己解析讀取數(shù)據(jù),解析數(shù)據(jù)成對(duì)象,切換回主線程,回調(diào)給上層。

這段空白的時(shí)間持續(xù)了很久。從我10年工作起到12年,因?yàn)閷憻┝酥貜?fù)的代碼,所以就得想辦法,把那些變化的地方封裝起來,也只是簡(jiǎn)單的封裝。好在官方出了AsyncTask,雖然坑很多,但如果再自己維護(hù)一個(gè)隊(duì)列,基本不會(huì)出現(xiàn)問題。更好的地方是數(shù)據(jù)格式從xml變成json了。gson解放了雙手,再也不用解析dom了。

早些時(shí)期的HTTP框架

后來慢慢出了不少真正的HTTP框架。Stay也借鑒了很多文章,封裝了一套適用于自身業(yè)務(wù)需求的框架。

這個(gè)時(shí)期的框架有個(gè)特點(diǎn),就是拼了命去支持所有類型。比方說Volley支持直接返回Bitmap。xUtils不僅大而全,而且連多線程下載也要支持。在資源匱乏的時(shí)代,它們的存在有它們的道理。但如果說現(xiàn)在還用Volley做圖片請(qǐng)求,還在用xUtils或Afinal里的各個(gè)模塊。那就說不過去了。術(shù)業(yè)有專攻,百家爭(zhēng)鳴的時(shí)期,難道不該選擇最好的那一個(gè)嗎?(Stay沒真的用過xUtils和Afinal這種組合框架,潛意識(shí)告訴我,它們有毒,一旦某個(gè)環(huán)節(jié)出問題或者需要擴(kuò)展,那代價(jià)就太大了)

Retrofit

好吧,介紹完HTTP框架的發(fā)展,讓我們單純的說說Retrofit吧。

tips:本文以retrofit最新版本2.0.1為例,大家也可以去github下源碼,找tag為'parent-2.0.1'就可以。目前代碼變動(dòng)比較大。2.0.1已經(jīng)使用okhttp3了,而我項(xiàng)目中2.0.0-beta2還是okhttp2.5。

retrofit的最大特點(diǎn)就是解耦,要解耦就需要大量的設(shè)計(jì)模式,假如一點(diǎn)設(shè)計(jì)模式都不懂的人,可能很難看懂retrofit。

先來看一張Stay畫的精簡(jiǎn)流程圖(如有錯(cuò)誤,請(qǐng)斧正),類圖就不畫了。

retrofit01.png

Stay在一些設(shè)計(jì)模式很明確的地方做了標(biāo)記。

外觀模式,動(dòng)態(tài)代理,策略模式,觀察者模式。當(dāng)然還有Builder模式,工廠等這些簡(jiǎn)單的我就沒標(biāo)。

先簡(jiǎn)述下流程吧:

  1. 通過門面Retrofit來build一個(gè)Service Interface的proxy

    retrofit03.png

  2. 當(dāng)你調(diào)用這個(gè)Service Interface中的某個(gè)請(qǐng)求方法,會(huì)被proxy攔截。
    retrofit02.png
  3. 通過ServiceMethod來解析invoke的那個(gè)方法 ,通過解析注解,傳參,將它們封裝成我們所熟悉的request。然后通過具體的返回值類型,讓之前配置的工廠生成具體的CallAdapter,ResponseConverter,這倆我們稍后再解釋。

  4. new一個(gè)OkHttpCall,這個(gè)OkHttpCall算是OkHttp的包裝類,用它跟OkHttp對(duì)接,所有OkHttp需要的參數(shù)都可以看這個(gè)類。當(dāng)然也還是可以擴(kuò)展一個(gè)新的Call的,比如HttpUrlConnectionCall。但是有點(diǎn)耦合??聪聢D標(biāo)注:


    retrofit031.png

    紅框中顯式的指明了OkHttpCall,而不是通過工廠來生成Call。所以如果你不想改源碼,重新編譯,那你就只能使用OkHttp了。不過這不礙事。(可能也是因?yàn)檫€在持續(xù)更新中,所以這塊可能后面會(huì)改進(jìn)的)

  5. 生成的CallAdapter有四個(gè)工廠,分別對(duì)應(yīng)不同的平臺(tái),RxJava, Java8, Guava還有一個(gè)Retrofit默認(rèn)的。這個(gè)CallAdapter不太好用中文解釋。簡(jiǎn)單來說就是用來將Call轉(zhuǎn)成T的一個(gè)策略。因?yàn)檫@里具體請(qǐng)求是耗時(shí)操作,所以你需要CallAdapter去管理線程。怎么管理,繼續(xù)往下看。

  6. 比如RxJava會(huì)根據(jù)調(diào)用方法的返回值,如Response<'T> |Result<'T>|Observable<'T> ,生成不同的CallAdapter。實(shí)際上就是對(duì)RxJava的回調(diào)方式做封裝。比如將response再拆解為success和error等。(這塊還是需要在了解RxJava的基礎(chǔ)上去理解,以后有時(shí)間可以再詳細(xì)做分析)

  7. 在步驟5中,我們說CallAdapter還管理線程。比方說RxJava,我們知道,它最大的優(yōu)點(diǎn)可以指定方法在什么線程下執(zhí)行。如圖

    retrofit04.png

    我們?cè)谧泳€程訂閱(subscribeOn),在主線程觀察(observeOn)。具體它是如何做的呢。我們看下源碼。
    retrofit05.png

    在adapt Call時(shí),subscribeOn了,所以就切換到子線程中了。

  8. 在adapt Call中,具體的調(diào)用了Call execute(),execute()是同步的,enqueue()是異步的。因?yàn)镽xJava已經(jīng)切換了線程,所以這里用同步方法execute()。

    retrofit06.png

  9. 接下來的具體請(qǐng)求,就是OkHttp的事情了,retrofit要做成的就是等待返回值。在步驟4中,我們說OkHttpCall是OkHttp的包裝類,所以將OkHttp的response轉(zhuǎn)換成我們要的T,也是在OkHttpCall中執(zhí)行的。

  10. 當(dāng)然具體的解析轉(zhuǎn)換操作也不是OkHttpCall來做的,因?yàn)樗膊恢罃?shù)據(jù)格式是什么樣的。所以它只是將response包裝成retrofit標(biāo)準(zhǔn)下的response。

  11. Converter->ResponseConverter,很明顯,它是數(shù)據(jù)轉(zhuǎn)換器。它將response轉(zhuǎn)換成我們具體想要的T。Retrofit提供了很多converter factory。比如Gson,Jackson,xml,protobuff等等。你需要什么,就配置什么工廠。在Service方法上聲明泛型具體類型就可以了。

  12. 最后,通過聲明的observeOn線程回調(diào)給上層。這樣上層就拿到了最終結(jié)果。至于結(jié)果再如何處理,那就是上層的事了。

再來回顧下Stay畫的流程圖:

retrofit01.png

這真是漫長(zhǎng)的旅行,Stay也是debug一個(gè)個(gè)單步調(diào)試才梳理出來的流程。當(dāng)然其中還有很多巧妙的解耦方式,我這里就不贅述了。大家可以看看源碼分析下,當(dāng)真是設(shè)計(jì)模式的經(jīng)典示例。

我想現(xiàn)在大家應(yīng)該對(duì)retrofit有所了解了。當(dāng)你再給別人介紹retrofit的時(shí)候,就別只說它的注解方式多新穎,多炫技了。注解式框架有很多的,像j2ee中一大把。所以注解算不得多精湛的技藝。最牛逼的還是它的解耦方式,這個(gè)套路沒有多年的實(shí)際架構(gòu)經(jīng)驗(yàn)是設(shè)計(jì)不出來的。

擴(kuò)展閱讀:

OkHttp, Retrofit, Volley應(yīng)該選擇哪一個(gè)?

Retrofit分析-謎之槽點(diǎn)

這么多開源框架,該用哪個(gè)好?

Retrofit分析-漂亮的解耦套路(視頻版)

Retrofit分析-經(jīng)典設(shè)計(jì)模式案例

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容