做者簡介java
本篇來自 小河馬 的投稿,分享了本身是如何進行 RxJava+Retrofit 的封裝。本文的技術點天然沒話說,另外對於這種模塊化的思路,但願能幫助到你們。最後提早祝你們週末愉快以及聖誕快樂!git
小河馬 的博客地址:github
http://www.jianshu.com/users/14354bcb0e09web
前言緩存
Retrofit 和 RxJava 已經出來好久了,不少前輩寫了不少不錯的文章,在此不得不感謝這些前輩無私奉獻的開源精神,能讓咱們站在巨人的肩膀上望得更遠。對於 RxJava 不是很瞭解的同窗推薦大家看扔物線大神的這篇文章:服務器
給Android開發者的RxJava詳解網絡
http://gank.io/post/560e15be2dca930e00da1083數據結構
一遍看不懂就看第二遍。Retrofit的使用能夠參考:併發
Android Retrofit2.0使用
框架http://wuxiaolong.me/2016/01/15/retrofit
本文內容是基於 Retrofit + RxJava 作的一些巧妙的封裝。參考了不少文章加入了一些本身的理解,請多指教。源碼地址:
https://github.com/Hemumu/RxSample
先放出 build.gradle:
本文是基於 RxJava1.1.0 和 Retrofit 2.0.0-beta4 來進行的。
初始化Retrofit
新建類Api,此類就是初始化 Retrofit,提供一個靜態方法初始化 Retrofit 很是簡單.
提供一個靜態方法初始化 Retrofit,手動建立了 OkHttpClient 設置了請求的超時時間。並在 OkHttp 的攔截器中增長了請求頭。注意這裏是爲全部的請求添加了請求頭,你能夠單獨的給請求增長請求頭,例如:
和 Retrofit 初始化不一樣的地方就在咱們添加了這兩句話:
和 Retrofit 初始化不一樣的地方就在咱們添加了這兩句話:
變成了:
返回值變成了 Observable,這個 Observable 不就是 RxJava 的可觀察者(即被觀察者)麼。
封裝服務器請求以及返回數據
用戶在使用任何一個網絡框架都只關心請求的返回和錯誤信息,因此對請求的返回和請求要作一個細緻的封裝。
咱們通常請求的返回都是像下面這樣:
若是大家的服務器返回不是這樣的格式那你就只有坐下來請他喝茶,跟他好好說(把他頭摁進顯示器)了。大不了就獻出你的菊花吧!
對於這樣的數據咱們確定要對 code 作出一些判斷,不一樣的 code 對應不一樣的錯誤信息。因此咱們新建一個 HttpResult 類,對應上面的數據結構。
這算是全部實體的一個基類,data 能夠爲任何數據類型。
咱們要對因此返回結果進行預處理,新建一個 RxHelper,預處理無非就是對 code 進行判斷和解析,不一樣的錯誤返回不一樣的錯誤信息,這還不簡單。Rxjava 的 map 操做符不是輕鬆解決。
喲,這不是輕鬆愉快 so seay麼!對 code 進行了判斷,code 爲0 就作對應更新UI或者其餘後續操做,不等於0就拋出異常,在 ApiException 中對 code 作處理,根據 message 字段進行提示用戶。
然而。。。RxJava 永遠比你想象的強大。RxJava 中那麼多操做符看到我身體不適,有個操做符 compose。由於咱們在每個請求中都會處理 code 以及一些重用一些操做符,好比用 observeOn 和 subscribeOn 來切換線程。
RxJava提供了一種解決方案:Transformer(轉換器),通常狀況下就是經過使用操做符Observable.compose()來實現。具體能夠參考:
避免打斷鏈式結構:使用.compose( )操做符
http://www.jianshu.com/p/e9e03194199e
新建一個 RxHelper 對結果進行預處理,代碼:
Transformer 實際上就是一個 Func1<Observable<T>, Observable<R>>,換言之就是:能夠經過它將一種類型的 Observable 轉換成另外一種類型的 Observable,和調用一系列的內聯操做符是如出一轍的。
這裏咱們首先使用 flatMap 操做符把 Obserable<HttpResult<T>>,轉換成爲 Observable<T> 在內部對code 進行了預處理。若是成功則把結果 Observable<T> 發射給訂閱者。反之則把 code 交給 ApiException 並返回一個異常,ApiException 中咱們對 code 進行相應的處理並返回對應的錯誤信息。
最後調用了頻繁使用的 subscribeOn() 和 observeOn() 以及 unsubscribeOn()。
處理ProgressDialog
在 Rxjava 中咱們何時來顯示 Dialog 呢。一開始以爲是放在 Subscriber<T> 的 onStart 中。onStart 能夠用做流程開始前的初始化。然而 onStart() 因爲在subscribe() 發生時就被調用了,所以不能指定線程,而是隻能執行在 subscribe() 被調用時的線程。因此 onStart 並不能保證永遠在主線程運行。
怎麼辦呢?
千萬不要小看了 RxJava,與 onStart() 相對應的有一個方法 doOnSubscribe(),它和 onStart() 一樣是在 subscribe() 調用後並且在事件發送前執行,但區別在於它能夠指定線程。默認狀況下,doOnSubscribe() 執行在 subscribe() 發生的線程;而若是在 doOnSubscribe() 以後有subscribeOn() 的話,它將執行在離它最近的 subscribeOn() 所指定的線程。
能夠看到在 RxHelper 中看到咱們調用了兩次 subscribeOn,最後一個調用也就是離doOnSubscribe() 最近的一次 subscribeOn 是指定的 AndroidSchedulers.mainThread() 也就是主線程。這樣咱們就就能保證它永遠都在主線運行了。這裏不得不感概 RxJava 的強大。
這裏咱們自定義一個類 ProgressSubscriber 繼承 Subscriber<T>:
初始化 ProgressSubscriber 新建了一個咱們本身定義的 ProgressDialog 而且傳入一個自定義接口 ProgressCancelListener。此接口是在 SimpleLoadDialog 消失 onCancel 的時候回調的。用於終止網絡請求。
ProgressSubscriber 其餘就很簡單了,在 onCompleted() 和 onError() 的時候取消 Dialog。須要的時候調用 showProgressDialog 便可。
處理數據緩存
服務器返回的數據咱們確定要作緩存,因此咱們須要一個 RetrofitCache 類來作緩存處理。
幾個參數註釋上面已經寫得很清楚了,不須要過多的解釋。這裏咱們先取了一個 Observable<T> 對象 fromCache,裏面的操做很簡單,去緩存裏面找個 key 對應的緩存,若是有就發射數據。
在 fromNetwork 裏面作的操做僅僅是緩存數據這一操做。最後判斷若是強制刷新就直接返回 fromNetwork反之用 Observable.concat() 作一個合併。concat 操做符將多個 Observable 結合成一個 Observable併發射數據。這裏又用了 first()。fromCache 和 fromNetwork 任何一步一旦發射數據後面的操做都不執行。
最後咱們新建一個 HttpUtil 用來返回用戶關心的數據,緩存,顯示Dialog在這裏面進行:
Activity生命週期管理
基本的網絡請求都是向服務器請求數據,客戶端拿到數據後更新UI。但也不排除意外狀況,好比請求回數據途中 Activity 已經不在了,這個時候就應該取消網絡請求。
要實現上面的功能其實很簡單,兩部分
隨時監聽 Activity(Fragment) 的生命週期並對外發射出去; 在咱們的網絡請求中,接收生命週期
並進行判斷,若是該生命週期是本身綁定的,如 Destory,那麼就斷開數據向下傳遞的過程
實現以上功能須要用到 Rxjava 的 Subject 的子類 PublishSubject
在你的 BaseActivity 中添加以下代碼:
這樣的話,咱們把全部生命週期事件都傳給了 PublishSubject 了,或者說 PublishSubject 已經接收到了並可以對外發射各類生命週期事件的能力了。
如今咱們要讓網絡請求的時候去監聽這個 PublishSubject,在收到相應的生命週期後取消網絡請求,這又用到了咱們神奇的 compose(),咱們須要修改 handleResult 代碼以下:
調用的時候增長了兩個參數一個是 ActivityLifeCycleEvent 其實就是一些枚舉表示 Activity 的生命週期
public enum ActivityLifeCycleEvent {
CREATE,
START,
RESUME,
PAUSE,
STOP,
DESTROY
}
另一個參數就是咱們在 BaseActivity 添加的 PublishSubject,這裏用到了 takeUntil(),它的做用是監聽咱們建立的 compareLifecycleObservable
compareLifecycleObservable 中就是判斷了若是當前生命週期和 Activity 同樣就發射數據,一旦compareLifecycleObservable 對外發射了數據,就自動把當前的Observable(也就是網絡請求的Observable)停掉。
固然有個庫是專門針對這種狀況的,叫
RxLifecycle
https://github.com/trello/RxLifecycle
不過要繼承他本身的 RxActivity,固然這個庫不僅是針對網絡請求,其餘全部的Rxjava均可以。有須要的能夠去看看。
最後新建一個 ApiService 存放咱們的請求:
使用起來就超級簡單了:
具體不少東西均可以在使用的時候具體修改,好比緩存我用的 Hawk。Dialog 是我本身定義的一個 SimpleLoadDialog。源碼已經給出請多指教!