眼下Retrofit+RxJava搭配的網絡請求框架非常流行,本着學習的態度,寫了一個相關的demo。寫着寫着就想朝着搭建一個項目框架的方向走。因而使用了一下MVP模式。git
RxJava 確實挺好用,我的特別喜歡這種「流式」的代碼風格,邏輯很清晰,起碼提供了一種相對的規範,開發者按照對應的流程寫代碼,後期的維護和拓展會簡單不少。github
MVP模式簡單說就是爲了解耦,各行各職,閱讀代碼,拓展功能代價不會那麼大(或許有些人認爲不必用MVP,直接在activity/fragment中寫代碼就行了,那隻能說你沒遇到到過相對大一點的項目,或者沒遇到「實習生」寫代碼,那酸爽,看代碼會看得你懷疑人生)服務器
在使用MVC開發Android應用的時候,原理上網絡
可是寫代碼的時候,你就會發現,好多跟view相關的操做都在activity中實現完成了,致使activity既是Controllor又是View,網上有人稱爲是MV模式,也所以致使activity的代碼量特別大,1000+的代碼很常見
後來,Presenter的出現,將Actvity,xml 視爲View層,Model不變,Presenter負責完成View層與Model層的交互。因而MVP是這樣的:架構
在網上看了一下MVP的使用demo,挺多人將一個頁面須要完成的操做,以及須要用到的控件所有定義到相關的View接口中,示例:框架
我的以爲,這個有點蛋疼
1.這樣view接口須要的方法太多了,有些實現(clearUserName())能夠放在activity中操做,第一不需將控件經過接口傳到Presenter中,第二我認爲這種算是對View的操做,仍是能夠看做View相關的。
2.咱們很難知道一個界面都要實現些什麼方法(若是包括對某個控件內容清空等),可是咱們不難知道一個activity須要實現哪些主要的功能,好比登陸頁面就一個登陸功能,或者再加多一個第三方登陸咯。函數
因此我以爲View接口中定義一些經常使用的方法,以及一些須要實現的方法就能夠了,經過回調內容,把控件賦值,數據展現等仍是放回在activity中操做,presenter只須要將對應的實體或者數據給activity就行了,activity怎麼展現,不用管,不關個人事情,作到各行各職。工具
或許有人會說,咦~你這都不是MVP,網上的MVP這些操做要放在presenter中的,這時我上去就給你一巴掌,咱們使用優秀的框架/架構是爲了學習它優秀的模式或者編碼風格,若是一味的循序漸進照着用,那將毫無心義!同時,咱們只有不斷改進,不斷推成出新才能使得技術不斷進步,若是前人不對MCV提出質疑,就不會有今天的MVP。佈局
因此我以爲View的接口應該這樣
一個BaseView,定義經常使用的方法,其餘頁面View接口繼承基類單元測試
這個基類怎麼寫看項目須要,按照開發者各自需求編寫。
如今寫一個登陸的LoginView,繼承BaseView同時添加特定的接口
這裏定義一個showResult(UserBean bean)
將User實體類傳給activity,用於展現用戶信息。
寫到這裏的時候的我突然更加堅決我所理解的MVP是對的,解耦嘛
Presenter:負責獲取或者構建UserBean
Activity:負責展現Presenter給過來的數據
以前看到過有人經過View接口將activity的控件幾乎「拷貝」到了presenter中,雖然實現了邏輯處理在Presenter,可是若是Presenter邏輯改動仍是會牽一髮動全身,要改動不少
如今這種方式挺好的,負責構建數據,不參與展現,也方便單元測試。對,就是這樣的。
Retrofit+RxJava確實是一種很不錯的搭配,RxJava能夠指定運行的線程,在網絡請求時,開啓線程耗時操做,響應結果時切換爲主線程操做UI。很是漂亮,代碼風格也贊,我我的稱爲流式操做,從上到下一步步表明操做的主要邏輯,比起傳統的迷之嵌套,迷之縮進好多了。
咱們知道RxJava使用訂閱模式,若是沒有及時取消訂閱,會致使內存泄漏,這個是很是糟糕的行爲,固然解決方式也很簡單,在對應的生命週期取消訂閱就好,不過我仍是懷着好奇之心Github一下,果真已經有人對此做出了貢獻RxLifecycle
經過綁定生命週期能夠很方便的管理訂閱與取消訂閱。
Github: https://github.com/trello/RxLifecycle
Retrofit+RxJava的使用仍是挺簡單的,不過相對於你們已經用在項目的網絡請求框架,它仍是須要進行加工的。好比說錯誤處理,配合RxLifecycle使用,以及不少人會問的,在MVP中使用的時候怎麼取消訂閱。
先看下最簡單的使用
接口代碼
使用代碼
代碼簡介,清晰,構建請求參數,構建被觀察者對象,以及傳入一個觀察者對象實現
訂閱回調onSubscribe
也能夠是開始的操做
成功回調onNext
失敗回調onError
監聽完成onComplete
或許開發者一眼就看出了onError
回調的對象是Throwable
這個不能忍啊,投入使用的框架確定得封裝,那就從這裏開始
在常見的網絡請求框架中通常會有兩個回調函數
定義onError
回調函數觸發的場景是:1.異常2.錯誤
1.異常:請求異常,解析數據出錯,網絡異常等等
2.錯誤:某一次請求邏輯錯誤,(例如:登陸錯誤)
將上述兩種狀況交給onError
回調函數處理
在請求邏輯成功的時候觸發一個onSuccess
函數。這樣監聽者就只須要兩個函數,一個失敗,一個成功,失敗提示給用戶,成功負責展現數據,跳轉頁面等
定義一個異常處理類ExceptionEngine
異常處理類中,都是常見的錯誤類型,咱們經過解析Throwable
轉換成統一的錯誤類ApiException
這個類很是簡單,一個狀態碼,一個錯誤信息,方便咱們開發調試。
不過仔細看代碼的同窗會發現,ServerException
這個是什麼鬼?「服務器返回的錯誤」?Throwable
怎麼知道這個錯誤類型是ServerException
?
其實這個ServerException
是咱們自定義的錯誤類型,通常咱們開發中都會跟服務器約定一種接口請求返回的數據。好比:
那麼咱們就能夠在解析服務端返回數據的時候,當code!=0,就拋出ServerException
OK,到這裏咱們常見的錯誤類型,異常等都處理完了,經過ExceptionEngine
轉化爲統一的錯誤類型ApiException
,在訂閱者回調onError(ApiException e)
就能夠很方便知道錯誤的狀態碼以及對應的描述信息。
咱們使用onErrorResumeNext(new HttpResultFunction<>())
操做符對Retrofit網絡請求拋出的Exception
進行處理,咱們定義HttpResultFunction
處理Retrofit拋出的Exception
,經過ExceptionEngine
轉化爲統一的錯誤類型ApiException
這一步是對錯誤,異常等的處理,若是某一個http請求沒有發生異常,或者網絡錯誤,就會走onNext
回調。
前面咱們約定,將服務器返回的邏輯錯誤也歸類到onError
。因此咱們在.map(new ServerResultFunction())
操做符中處理服務器返回的結果是否正確(這裏指邏輯正確,即code==0),若是code!=0,就拋出ServerException
解析服務器返回結果 HttpResponse
,這個類由開發者自行設置,根據實際狀況來定義字段,這裏我假設後臺返回的字段有
String msg; int retCode; Object result;
這裏Result
咱們使用Object
由於接口時通用的,服務端返回的接口類型也是多樣的,多是列表
,也多是JSON
對象,或者String
字符串,因此這裏咱們使用Object,在數據解析的時候在轉化成爲具體的類型
嗯,錯誤處理搞定了,那就是簡單的封裝一下Retrofit 和RxJava以及使用RxLifecycle
RxJava使用訂閱模式,那咱們就須要封裝一個被訂閱者,一個訂閱者,以及使用RxLifecycle自動管理訂閱的生命週期
構建Api接口類
構建Retrofit工具類獲取retrofit實例
構建網絡請求(被訂閱對象)
在HttpRxObservable
咱們構建一個被訂閱者Observable
而且設置了錯誤處理,同時添加了生命週期管理。
處理訂閱者Observer
使用網絡請求的過程當中咱們確定會遇到取消請求的場景,這裏咱們實現一個HttpRequestListener
,爲每個請求添加惟一的TAG
用來標識具體的每個請求,開始請求時保存TAG,請求成功/失敗移除標誌,同時TAG也用作取消請求的標誌。
編寫一個測試類,示例如何使用Retrofit
使用RxLifecycle
管理訂閱生命週期activity須要繼承RxActivity
。開篇也提到MVP的時候,接下來就說說在MVP中如何使用。
定義一個Presenter基類
JAVA弱引用,管理View的引用,以及activity的引用,避免強引用致使資源沒法釋放而形成的內存溢出,
寫代碼的時候想到了一個很巧妙的方式:Presenter中傳如一個activity,同時實現Activity生命週期監聽,在onDestroy中移除View和Activity的引用,我的以爲這個很是不錯。看官能夠客觀評價一下優劣。
登陸Presenter
LoginActivity
以上是我對MVP的一點理解,以及對RxJava2+Retrofit2+RxLifecycle2進行的封裝,因爲編寫demo的時候是朝着構建一個項目框架走的,因此沒有貼完的代碼就請移步到個人Github克隆完整版本,盡情的擼吧。
我的認爲這個搭配仍是可行的,而且已經投入都項目中。好產品必定要本身先使用,承認。哈哈哈