MVP這個話題也是討論了很久很久的闰歪,熱度一直不減则披,甚至google官方也很認可MVP在Android中的地位。
而我最近一個項目也參照google的那個MVP架構沪斟,發(fā)現并怎么好用支示。
果然架構這種東西需要自己思考刊橘,根據不同的項目進行變更,MVP MVC MVVM總的來說就是一個架構模式颂鸿,具體應該怎么實現還是需要依賴于自己不斷的探索促绵,照搬別人的項目的話是不可能適合你的項目的。所以網上的MVP項目也是五花八門嘴纺,看得我欲仙欲死败晴。
google工程師也說了,他們放出的那個Android Architecture只是作為參考栽渴,具體怎么實現mvp架構取決于你尖坤。
而我也在這篇文章中聊一下我這一個月來照搬Google MVP的感受。
可以先看看這篇文章簡單的了解一下google官方mvp
Android官方MVP架構示例項目解析
一闲擦、 V層:Fragment
google 用Fragment這個控件作為MVP中的View層慢味,什么回事?
Fragment作為View墅冷,那么在Activity就可以初始化Presenter纯路,View和其他一些依賴,讓依賴注入獨立于MVP外寞忿,Activity看起來就像一個Injector驰唬。如果Activity作為View的話,那么你需要在Activity中初始化一大堆依賴,View就不是單純的View了叫编。
這雖然看起來很符合MVP的架構思想辖佣,進一步減少了View的工作。但實際上搓逾,不好的地方也是很多的卷谈。
寫項目的時候,不僅要多敲一個Fragment恃逻,而且在Activity中也是做反復性的工作:new Fragment,addFragment藕施, new Present……
而且Fragment用起來并沒有Activity那么便利寇损,還存在各種莫名其妙的bug,最致命的一點就是:
我們完全可以使用Dagger2進行依賴注入裳食,那么Fragment作為View的好處幾乎就沒有了矛市。
在CleanArchitecture這個開源項目中,雖然也是用Fragment作為View層诲祸,但好歹別人用setRetainInstance()維持Presenter白抢簟(presenter生命周期,下面會講到)救氯,不過這方法用不好的話很容易導致內存泄漏……
所以找田,最終我還是會選擇Activity作為View,除非某些頁面確實需要用到Fragment着憨。
關于Fragment可以看看這篇文章:我為什么不主張使用Fragment
二墩衙、Contract協議類
google用一個Contract類定義了View層接口和Presenter層接口,這看起來是很不錯的設計甲抖,看起來很符合依賴倒置原則漆改。
但是Presenter真的有必要實現接口嗎?
在MVP模式中准谚,Presenter是高層次模塊挫剑,而View是低層次模塊。
而使用依賴倒置原則主要是為了高層和低層模塊的解耦柱衔,方便替換低層次模塊的時候不會影響到高層模塊樊破,所以在MVP模式中,View需要實現接口唆铐,你可以隨時將View替換成Activity捶码,Fragment或者其他,并不會印象到Presesnter或链。
View使用接口還有另外一個好處:方便測試惫恼。你不可能在對Presenter進行單元測試的時候去Mock一個xxxActivity對吧……
而View雖然也依賴于Presenter,但是View和Presenter是一一對應的澳盐,Presenter只會有一個祈纯,并不可能出現其他實現令宿,所以Presenter實現接口完全是多余的,不僅多了一個無意義的類腕窥,還累著自己粒没。
并且,在View中想看Presenter代碼的時候簇爆,ctrl+左鍵點擊Presenter提示一大堆同名的Presenter癞松。選擇其中一個點進去之后,跳轉到的是contract類入蛆,最終結果你還是需要到目錄去找……
關于Presenter到底該不該使用接口解耦的一篇文章响蓉,我個人是非常認同作者的。
不要再給MVP中Presenter寫接口了
三哨毁、P層的生命周期
這一塊也是MVP架構中的一個難點
google的mvp很明顯沒有做額外的Presenter的生命周期管理枫甲,讓它隨著View的生命周期結束而結束。
這看起來沒什么問題扼褪,但是你們想想想幻,Presenter往往會保存View的一些狀態(tài),比如保存是否已經請求過數據的變量话浇,或者某些請求參數脏毯。
當Activity或者Fragment因為某些原因生命周期重走了(比如旋轉屏幕或者被系統回收),你的Presenter也會重新實例化一個幔崖。
如果用戶沒事做一直來回的旋轉屏幕抄沮,那么你的Presenter就一次次的實例化,一次次的請求網絡……最終可能導致內存溢出或者ANR
不過我們國內的app一般都禁止橫屏岖瑰,所以這一點也不是很重要叛买,但始終算是一個不好的地方吧。
對于延長Activity生命周期的方法有好幾種方式
可以看看這篇文章通過Loader延長Presenter生命周期
之前說的使用Fragment的setRetainInstance也是其中一種方法
四蹋订、Model層(Repository層)
在上面的圖中率挣,也可以看到Google的Model層使用了多種數據源。
內存露戒,本地椒功,網絡。
當接收到Prestenr請求數據的時候智什,Repository就會從內存中取數據动漾,如果沒有就從本地取,本地沒有就網絡請求荠锭。
也不用擔心每次請求到的數據都是緩存旱眯,因為Repository中還有一個變量判斷數據是否過期。
這種Model層的設計方式還是很不錯的,但是Repository中的代碼看起就有點混亂了删豺。
如果單個Repository中的數據量比較多的情況下共虑,那么看起來會非常混亂呀页,因為Repository中是管理了多個數據源的妈拌。
我覺得CleanArchitecture的model層設計比google的來的清晰,數據源用一個Factory類管理蓬蝶,并且用Cache類封裝緩存尘分,可以管理緩存的過期時間等。比起google直接在Repository中處理數據源邏輯要好些丸氛。
還有另外一點就是培愁,有些數據是不需要本地保存的,每次都應該保證是最新的雪位,例如新聞列表竭钝,這時候該怎么辦梨撞。
我個人認為應該統一風格雹洗,就算不需要本地緩存,也務必使用多數據源結構的Repository卧波,雖然類會多了时肿,但是可以讓你的項目更加清爽。
如果你的項目中港粱,只有少數一兩個接口是需要本地緩存的螃成,那么還是不要用多數據源的設計了。這是過度設計查坪,畫蛇添足寸宏。
五、總結
googlesample的MVP架構用來學習的話是很不錯的例子偿曙,至少比用其他人過度封裝的mvp要簡單點氮凝。
但是要在實際開發(fā)中使用mvp架構,最好是參照google和clean Architecture這兩個比較熱門的例子望忆,然后花個幾天時間認真思考才動手罩阵。
Model層而账,Presenter層的設計席爽,還有統一處理公共參數,統一處理異常等都是值得思考的東西奥秆。