Android官方MVP架構示例專案解析
前段時間Google在Github推出了一個專案,專門展示Android引用各種各樣的MVP架構,算是官方教程了。趁著還新鮮,讓我們來拋磚引玉一探究竟,看看在Google眼裡什麼樣算是好的MVP架構
App架構在Android開發者中一直是討論比較多的一個話題,目前討論較多的有MVP、MVVM、Clean這三種。google官方對於架構的態度一直是非常開放的,讓開發者自主選擇組織和架構app的方式,期望能留給開發者更多的靈活性.
由於沒有一套權威的架構實現,現在很多App專案中在架構方面都有或多或少的問題。第一種常見問題是沒有架構,需求中的一個頁面對應專案中的一個activity或一個fragment,所有的介面響應程式碼、業務邏輯程式碼、資料請求程式碼等等都集中在其中。第二種
常見的問題是架構實現的不斷變化,不斷在各種架構間搖擺,一直找不到一個適合自己的架構。
就在近日,google在官方示例中給出了一系列不同架構的app實現,這對於一直困惑於到底該用何種架構的android開發者來說確實是福音,開發者只要根據自己專案的情況,在不同的實現中選擇一種即可,當然google也明確表示了這些示例只是用來做參考,而並不是要為了當做標準,下面先為大家簡單介紹下此專案。
專案介紹
Google把這個專案命名為:Android架構藍圖。
下面的內容引用自專案說明:
專案目的是通過展示各種架構app的不同方式來幫助開發者解決架構問題。專案中通過不同的架構概念及方式實現了功能相同的app。你可以用示例來當做參考,或是乾脆拿來當做建立app專案的基礎。專案中,希望大家能把關注點集中到程式碼結構、整體架構、可測試性、可維護性這四個方面。當然實現app有很多種方式,千萬不要把它當做定式。
專案中有哪些示例
目前已經完成的示例有
todo-mvp(mvp基礎架構示例)
todo-mvp-loaders(基於mvp基礎架構專案,獲取資料部分使用了Loaders架構)
todo-mvp-databinding(基於mvp基礎架構專案,使用了資料繫結元件)
仍在進展中的示例有
todo-mvp-contentproviders(基於mvp基礎架構專案,使用了Content Providers)
todo-mvp-clean(基於mvp基礎架構專案,使用了clean架構的概念)
todo-mvp-dagger(基於mvp基礎架構專案,使用了dagger2進行依賴注入)
如何進行選擇
這個還是需要開發者自己來做決定,每個專案的說明檔案中都說明了該實現的特性。app規模、團隊狀況、維護工作量的大小、平板是否支援、程式碼簡潔程度偏好,這些都會影響你的選擇。
到了這裡,想必大家都很想一探究竟了,到底官方示例是如何實現的呢?還是那句話,原始碼面前,了無祕密。為了能夠更好的理解官方mvp架構實現,下面我們從原始碼的角度來分析todo-mvp(mvp基礎架構示例)的實現。我們先從專案的整體組織方式開始,再看專案究竟使用了哪些元件,最後當然是最重要的具體mvp的實現方式。
原始碼分析
專案程式碼組織方式
專案含一個app src目錄,4個測試目錄,分別是androidTest(UI層測試)、androidTestMock(UI層測試mock資料支援)、test(業務層單元測試)、mock(業務層單元測試mock資料支援)。src目錄的程式碼組織方式完全是按照功能來組織的,功能內部分為xactivity、xcontract、xfragment、xpresenter四個類檔案(x代表業務名稱)。
平時用到較多的另一種組織方式是按照型別,比如按照activity、adapter、fragment、contract、presenter進行劃分,不同的類檔案分別放到不同的目錄中,筆者覺得兩種方式沒有什麼太大的區別,完全看個人喜好了。
元件使用
由於專案是基於gradle進行編譯的,所以我們可以從build.gradle檔案看到專案依賴的全貌。
Guava
專案中使用到了Guava庫(https://github.com/google/guava),該庫是Google在基於java的專案中都會引用到得一個庫,庫中包含大約14k的方法數,是個很大的庫,其中包含了集合、快取、併發、基本註解、字串處理、io處理等等。專案中使用Guava庫主要是處理null這種不安全的情況,因為一般我們在使用有可能為null的物件時,一般會增加一次判斷,程式碼如下:
而如果有Guava的時候,可以通過如下方式
這樣面對空的時候,就不用再多寫很多程式碼了,確實是方便了很多。但是不建議為了null安全直接引入如此大的一個庫,因為我們都知道android apk的65k方法數限制,如果要用的話可以把原始碼中涉及到得部分直接拿出來用。當然Guava中還有很多重要的功能,其他功能讀者可以自行研究,關於Guava就先到這裡了。
測試相關元件
示例專案在可測試方面做的非常好,由於對檢視邏輯(view層)和業務邏輯(presenter層)進行了拆分,所以我們就可以對UI、業務程式碼分別進行測試。為了進行UI測試引入了Espresso,為了對業務層進行單元測試引入了junit,為了生成測試mock物件引入了mockito,為了支撐mockito又引入了dexmaker,hamcrest的引入使得測試程式碼的匹配更接近自然語言,可讀性更高,更加靈活。
專案MVP實現方式
這節我們就具體來看官方示例到底是如何實現mvp的。這裡我們先看下總體的輪廓,關於專案中業務程式碼我們僅列出了任務詳情頁(taskDetail)的相關類,其他業務程式碼類似。
基類
我們首先來看兩個Base介面類,BasePresenter與BaseView,兩類分別是所有Presenter與View的基類。
BasePresenter中含有方法start(),該方法的作用是presenter開始獲取資料並呼叫view中方法改變介面顯示,其呼叫時機是在Fragment類的onResume方法中。
BaseView中含方法setPresenter,該方法作用是在將presenter例項傳入view中,其呼叫時機是presenter實現類的建構函式中。
契約類
與筆者之前見到的所有mvp實現都不同,官方的實現中加入了契約類來統一管理view與presenter的所有的介面,這種方式使得view與presenter中有哪些功能,一目瞭然,維護起來也方便,例項如下
activity在mvp中的作用
activity在專案中是一個全域性的控制者,負責建立view以及presenter例項,並將二者聯絡起來,下面是activity中建立view及presenter的程式碼
我們可以從上面看到整個建立過程,而且要注意的是建立後的fragment例項作為presenter的建構函式引數被傳入,這樣就可以在presenter中呼叫view中的方法了。
mvp的實現與組織
例項中將fragment作為view層的實現類,為什麼是fragment呢?有兩個原因,第一個原因是我們把activity作為一個全域性控制類來建立物件,把fragment作為view,這樣兩者就能各司其職。第二個原因是因為fragment比較靈活,能夠方便的處理介面適配的問題。我們先看view的實現,我們只挑一部分重要的方法來看
上面可以看到setPresenter方法,該方法繼承於父類,通過該方法,view獲得了presenter得例項,從而可以呼叫presenter程式碼來處理業務邏輯。我們看到在onResume中還呼叫了presenter得start方法,下面我們再看presenter的實現
presenter建構函式中呼叫了view得setPresenter方法將自身例項傳入,start方法中處理了資料載入與展示。如果需要介面做對應的變化,直接呼叫view層的方法即可,這樣view層與presenter層就能夠很好的被劃分。
最後還剩下model層實現,專案中model層最大的特點是被賦予了資料獲取的職責,與我們平常model層只定義實體物件截然不同,例項中,資料的獲取、儲存、資料狀態變化都是model層的任務,presenter會根據需要呼叫該層的資料處理邏輯並在需要時將回調傳入。這樣model、presenter、view都只處理各自的任務,此種實現確實是單一職責最好的詮釋。
總結
到這裡我們就基本分析完了,我們再來整體看下官方的實現方式有哪些特性。
首先是複雜度,我們可以從上面的分析看出整體的複雜度還是較低的,易學的;然後是可測試性,由於將UI程式碼與業務程式碼進行了拆分,整體的可測試性非常的好,UI層和業務層可以分別進行單元測試;最後是可維護性和可擴充套件性,由於架構的引入,雖然程式碼量有了一定的上升,但是由於界限非常清晰,各個類職責都非常明確且單一,後期的擴充套件,維護都會更加容易。有了這個架構之後,我們再回頭看下之前的實現是不是有很多不足,沒有關係,那麼接下來就是在專案中進行實踐的時間了。