天天看點

談談網絡庫和Retrofit一.網絡子產品需要具備什麼能力?二.為什麼Retrofit是個好選擇三. Retrofit業務分析四.Retrofit技術點五.設計模式

本文目錄如下

網絡子產品需要具備什麼能力 為什麼Retrofit是個好選擇 Retrofit業務分析 Retrofit技術點 設計模式

常見的需求下圖:

談談網絡庫和Retrofit一.網絡子產品需要具備什麼能力?二.為什麼Retrofit是個好選擇三. Retrofit業務分析四.Retrofit技術點五.設計模式

下面解釋一下重要的部分.

為了讓頁面快速展現,很多頁面需要先加載緩存.

通用政策是

1.先加載緩存;

2.然後做網絡請求

3.網絡請求成功後重新整理頁面,并且更新緩存資料

這裡涉及到,緩存要存在哪裡. 一般也是兩種方案:

業務側做緩存. 每個頁面自己維護緩存,一般存在db/sp/檔案系統中 網絡側做緩存, 業務做網絡請求的時候,可以要求傳回緩存資料.

方案1:适用于存儲需要檢索資料的情況. 比如資料存在db中,可以用sql查詢. 缺點是業務側需要實作緩存政策,較麻煩.

方案2: 業務側調用簡單,适用場景非常廣泛.

是以在網路側支援緩存, 是一個很普遍的方案.

這個是基于這幾種前提.

App有登入功能 App登入通過 AccessToken/RefreshToken實作

簡單說明 AccessToken失效後會發生什麼:

AccessToken失效

做網絡請求,服務端會傳回結果說AccessToken失效

此時網絡請求是失敗了

用戶端利用RefreshToken 重新換AccessToken.

拿着新AccessToken 重發網絡請求.

業務側拿到正确結果

一般AccessToken失效是比較頻繁的, 如果沒有自動重新請求機制, 每次AccessToken失效使用者都能感覺到,這樣體驗很不好. 是以一般要在網絡庫/登入子產品之間或者上層做一個封裝解決這個問題..

最好是能:

取消一次網絡請求

某個頁面退出時,能取消整個頁面對應的網絡請求.

資源嗎,能省點就省點

很多請求是需要需要刷UI的, 這樣就不需要主動post到UI線程了.

選開源庫,有幾個點很重要.

成熟的項目明顯的坑少. 是以一個應用廣泛的庫是一個穩妥的選擇.

Retrofit: Square出品, 2萬+ star,一直在更新

是代碼總會有bug的, 有問題要能看明白,可以選擇規避或者自行解決. 代碼龐大或者邏輯複雜時,排查問題就是一個很痛苦的過程

Retrofit 代碼量少,結構清晰
談談網絡庫和Retrofit一.網絡子產品需要具備什麼能力?二.為什麼Retrofit是個好選擇三. Retrofit業務分析四.Retrofit技術點五.設計模式

業務是變化的, 要在預期的業務變化内, 目前庫要能cover住, 如果開發幾版發現不能滿足拓展的需求, 臨時換庫,那會帶來很多工作量和bug

Retrofit 在解耦上做的很棒,拓展性高

在這點上很重要,引入一個庫如果要一并帶入很多它的依賴庫,會有很大的問題:

會增大包的體積

會讓庫變得不好維護,鍊條上的每個庫都可能有問題.

最大的問題是, 這些依賴庫可能會和App的其他依賴庫沖突. 會産生類沖突,版本沖突. 排查這些沖突是一個很痛苦的過程.(在這點上, 集團的依賴庫這個問題尤為嚴重)

Retrofit目前依賴于Okhttp3, 考慮到OKhttp3也很流行,可以一并引入

做為一個網絡庫Okhttp的封裝, Retrofit需要處理3部分問題:

允許業務拓展哪些環節. 這些拓展的注冊,和什麼情況下生效 拓展是否靈活

Retrofit允許配置的是 CallAdapter,RequestBodyConverter,ResponseConvert.

CallAdapter: 負責調用OkHttpCall發起請求,處理回調分發 RequestBodyConverter: 在建構Request的時候, 建構body ResponseConverter: 轉換網絡請求結果.

Retrofit發起網絡請求最終走的的OKHttpCall.

網絡請求的流程套路大家都一樣, 都是:

"業務發起請求"->"建構Request"->"發起請求"->"解釋請求"->"回調業務".

下面是他的調用流程, 藍色部分是自定義子產品.

談談網絡庫和Retrofit一.網絡子產品需要具備什麼能力?二.為什麼Retrofit是個好選擇三. Retrofit業務分析四.Retrofit技術點五.設計模式

在Retrofit初始化的時候, 允許添加CallAdapterFactory和ConverterFactory.

注冊和擷取的流程如下.

按注冊的順序擷取,隻要找到了就就結束查找.

談談網絡庫和Retrofit一.網絡子產品需要具備什麼能力?二.為什麼Retrofit是個好選擇三. Retrofit業務分析四.Retrofit技術點五.設計模式

每一個請求聲明是一個函數, 他包含3部分資訊:

Return Type Method Annotation Parameter Annotation
談談網絡庫和Retrofit一.網絡子產品需要具備什麼能力?二.為什麼Retrofit是個好選擇三. Retrofit業務分析四.Retrofit技術點五.設計模式

對于CallAdapter/RequestBodyConverter/ResponseConvert可以擷取到這3部分資訊.然後做相應操作,過程是非常靈活.

關于Type下面這個文章講的比較好

<a href="http://blog.csdn.net/yuanyang5917/article/details/53130187">Retrofit完全解析(三):Type&lt;基礎詳解&gt;</a>

對于方法

方法有三部分資訊

函數傳回值

方法體上的Annotaion

參數中的Annotation

Retrofit中根據這3部分資訊, 比對CallAdapter/Converter,生成ServiceMethod, 中間用了大量的泛型解釋.代碼集中展現在 Utils/ServiceMethod/CallAdapter/Converter上.

1.不能修改的類用final修飾

2.new ConcurrentHashMap&lt;&gt;()處理并發,取得時候加上synchronized判斷

3.adapterFactories = unmodifiableList(adapterFactories); // Defensive copy at call site. 做參數保護

<a href="https://github.com/square/okhttp/tree/master/mockwebserver">MockWebServer-github</a>

com.squareup.okhttp3:mockwebserver

比較強大的網絡模拟工具, 配合Okhttp用很友善

談談網絡庫和Retrofit一.網絡子產品需要具備什麼能力?二.為什麼Retrofit是個好選擇三. Retrofit業務分析四.Retrofit技術點五.設計模式
談談網絡庫和Retrofit一.網絡子產品需要具備什麼能力?二.為什麼Retrofit是個好選擇三. Retrofit業務分析四.Retrofit技術點五.設計模式
作者: stay4it

<code>Retrofit</code>給我們暴露的方法和類不多。核心類就是<code>Retrofit</code>,我們隻管配置<code>Retrofit</code>,然後做請求。剩下的事情就跟上層無關了,隻需要等待回調。這樣大大降低了系統的耦合度。對于這種寫法,我們叫外觀模式(門面模式)。

幾乎所有優秀的開源library都有一個門面。比如<code>Glide.with()</code>, <code>ImageLoader.load()</code>, <code>Alamofire.request()</code>。有個門面友善記憶,學習成本低,利于推廣品牌。 Retrofit的門面就是<code>retrofit.create()</code>

當我們自己寫的代碼的時候盡量也要這樣來做。

比如我們有一個獨立并公用的子產品,需要供其他子產品來調用。比如download,location,socialshare等

最好我們寫一個module,将所有相關的代碼都放在這個module中。這是第一步。

第二步,為你的module提供一個漂亮的門面。比如下載下傳的DownloadManager, 經緯度的LocationTracker, 社交分享的SocialManager。它們做為功能子產品的入口,要盡量的簡潔,方法命名好記易了解,類上要有完整的示例注釋

第三步,閉門造車。不管你在裡面幹什麼,外面都是不知道的,就像薛定谔的那隻貓,外層不調用它,永遠不知道它是否好用。

不過為了以後好維護,不給他人留坑,還是盡量寫的工整一些。

<a href="http://www.jianshu.com/p/2f518a4a4c2b">Java靜态代理和動态代理介紹</a>

再來說動态代理。以往的動态代理和靜态代理使用的場景是類似的。都想在delegate調用方法前後做一些操作。如果我的代理類有很多方法,那我得額外寫很多代碼,是以這時候就引入了動态代理。通過動态設定delegate,可以處理不同代理的不同方法。看不懂沒關系,直接上代碼:

内部<code>Converter,CallAdapter</code>都用了抽象工廠模式, <code>Interface</code>和<code>Factory</code>放到了一個類中,減少類檔案的數量, Factory生成對應Interface的類,明确比對關系.

如果你已經看過retrofit源碼,很可能被<code>CallAdapter</code>玩壞。這個<code>CallAdapter</code>不是那麼好了解。先抛開代碼,我們來看看擴充卡模式。

<code>Adapter</code>簡單來說,就是将一個已存在的東西轉換成适合我們使用的東西。就比方說電源<code>Adapter</code>。出國旅遊都要帶轉接頭。比方說,<code>RecyclerView</code>裡的<code>Adapter</code>是這麼定義的。 <code>Adapters provide a binding from an app-specific data set to views</code>。

再回來看看<code>Retrofit</code>,為什麼我們需要轉接頭呢。那個被轉換的是誰?我們看看<code>CallAdapter</code>的定義。<code>Adapts a {@link Call} into the type of {@code T}</code>. 這個<code>Call</code>是<code>OkHttpCall</code>,它不能被我們直接使用嗎?被轉換後要去實作什麼特殊的功能嗎?

我們假設下。一開始,<code>retrofit</code>隻打算在<code>android</code>上使用,那就通過靜态代理<code>ExecutorCallbackCall</code>來切換線程。但是後來發現<code>rxjava</code>挺好用啊,這樣就不需要<code>Handler</code>來切換線程了嘛。想要實作,那得轉換一下。将<code>OkHttpCall</code>轉換成<code>rxjava(Scheduler)</code>的寫法。再後來又支援<code>java8(CompletableFuture)</code>甚至居然還有iOS支援。大概就是這樣一個套路。當然我相信square的大神肯定一開始就考慮了這種情況,進而設計了<code>CallAdapter。</code>

談談網絡庫和Retrofit一.網絡子產品需要具備什麼能力?二.為什麼Retrofit是個好選擇三. Retrofit業務分析四.Retrofit技術點五.設計模式

擴充卡模式就是,已經存在的OkHttpCall,要被不同的标準,平台來調用。設計了一個接口CallAdapter,讓其他平台都是做不同的實作來轉換,這樣不花很大的代價就能再相容一個平台。666。

裝飾模式跟靜态代理很像。

每次一說裝飾模式,就想成decorator,實際上叫wrapper更直覺些。既然是wrapper,那就得有源的句柄,在構造wrapper時得把source作為參數傳進來。wrapper了source,同樣還wrapper其他功能。

代理模式,Proxy Delegate,實際上Delegate也不知道自己被代理了,Proxy僞裝成Delegate來執行,既然是proxy,那proxy不應該提供delegate沒有的public方法,以免被認出來。

抛開理論的描述,我們直接來看下面的代碼。

談談網絡庫和Retrofit一.網絡子產品需要具備什麼能力?二.為什麼Retrofit是個好選擇三. Retrofit業務分析四.Retrofit技術點五.設計模式

你可以将ExecutorCallbackCall當作是Wrapper,而真正去執行請求的源Source是OkHttpCall。之是以要有個Wrapper類,是希望在源Source操作時去做一些額外操作。這裡的操作就是線程轉換,将子線程切換到主線程上去。

<a href="http://www.jianshu.com/p/45cb536be2f4">Retrofit分析-漂亮的解耦套路</a>

<a href="http://www.jianshu.com/p/fb8d21978e38">Retrofit分析-經典設計模式案例</a>

<a href="http://www.jianshu.com/p/050c6db5af5a">Android主流網絡請求開源庫的對比(Android-Async-Http、Volley、OkHttp、Retrofit)</a>

<a href="http://www.jianshu.com/p/0c055ad46b6c">Android:手把手帶你深入剖析 Retrofit 2.0 源碼</a>

繼續閱讀