轉(zhuǎn)載至:http://www.lxweimin.com/p/9a6845b26856
“Android MVP 詳解(下)”已經(jīng)發(fā)布,歡迎大家提建議。
MVP 在 Android 上的使用其實(shí)已經(jīng)有挺長(zhǎng)一段時(shí)間了,長(zhǎng)到似乎有點(diǎn)“過時(shí)”了(目前風(fēng)頭正勁的是MVVM),那為什么現(xiàn)在還要講 MVP。今天我想要討論它的主要原因有如下幾點(diǎn):
1. MVP 并未過時(shí),值得我們研究
2. 目前關(guān)于 MVP 的資料都不算太詳盡
3. 由于能力和時(shí)間有限,本人拖到最近才下定決心寫
說(shuō)明:本文只是拋磚引玉,疏漏之處敬請(qǐng)諒解。
MVP 詳解思維導(dǎo)圖
目錄
前言
一、什么是MVP
二、MVX解析
三、MVX與三層架構(gòu)
四、Android上MVP的幾種實(shí)現(xiàn)
五、最佳實(shí)踐
六、進(jìn)階與不足
前言
2014年年底偶然得知在Android開發(fā)中出現(xiàn)了MVP這種模式,當(dāng)時(shí)覺得這東西挺好,正好趕上公司要做一個(gè)新的小項(xiàng)目,于是嘗試了一下。仿照網(wǎng)上的Demo分出View、Model、Presenter層,抽取View接口,看起來(lái)像那么回事的用MVP完成了整個(gè)項(xiàng)目。因?yàn)轫?xiàng)目簡(jiǎn)單,期間也沒有遇到什么坑,但是總覺得還有那些地方不對(duì)。當(dāng)時(shí)網(wǎng)上一些關(guān)于Android MVP的介紹都有點(diǎn)淺嘗輒止,一個(gè)登錄或者根據(jù)地區(qū)查詢天氣等的小Demo,沒有實(shí)際在項(xiàng)目中應(yīng)用的示例,所以在用MVP做完一個(gè)小項(xiàng)目之后還是不敢在主項(xiàng)目中輕易嘗試。首先,主項(xiàng)目比較混亂,改動(dòng)起來(lái)工作量很大,而工期經(jīng)常較緊,時(shí)間不允許;其次,知道自身對(duì)MVP理解還不夠,怕掉坑里去;最后,也是最重要的一點(diǎn),當(dāng)時(shí)的項(xiàng)目不是按功能模塊劃分的包結(jié)構(gòu),如果改為MVP那是真的就回不到過去了。好了,廢話不多說(shuō),今天主要是想分享一下,本人對(duì)MVP的淺見,以及如何使用MVP模式搭建一個(gè)項(xiàng)目框架。純屬一家之言,不足之處,請(qǐng)見諒。
一、什么是 MVP
1.1. MVP 的定義
MVP,全稱?Model-View-Presenter
要說(shuō)MVP那就不得不說(shuō)一說(shuō)它的前輩——MVC。
MVC(Model-View-Controller,模型-視圖-控制器)模式是80年代Smalltalk-80出現(xiàn)的一種軟件設(shè)計(jì)模式,后來(lái)得到了廣泛的應(yīng)用,其主要目的在于促進(jìn)應(yīng)用中模型,視圖,控制器間的關(guān)注的清晰分離。MVP(Model-View-Presenter,模型-視圖-表示器)模式則是由IBM開發(fā)出來(lái)的一個(gè)針對(duì)C++和Java的編程模型,大概出現(xiàn)于2000年,是MVC模式的一個(gè)變種,主要用來(lái)隔離UI、UI邏輯和業(yè)務(wù)邏輯、數(shù)據(jù)。也就是說(shuō),MVP 是從經(jīng)典的模式MVC演變而來(lái),它們的基本思想有相通的地方:Controller/Presenter負(fù)責(zé)邏輯的處理,Model提供數(shù)據(jù),View負(fù)責(zé)顯示。
說(shuō)明:按照View和Presenter之間的交互方式以及View本身的職責(zé)范圍,Martin Folwer將MVP可分為PV(Passive View)和SoC(Supervising Controller)兩種模式。
Passive View
顧名思義,PV(Passive View)是一個(gè)被動(dòng)的View,針對(duì)包含其中的UI元素(比如控件)的操作不是由View自身來(lái)操作,而交給Presenter來(lái)操控。
Supervising Controller
在SoC(Supervising Controller)模式下,為了降低Presenter的復(fù)雜度,將諸如數(shù)據(jù)綁定和格式化這樣簡(jiǎn)單的UI處理邏輯邏輯轉(zhuǎn)移到View中,這些處理邏輯會(huì)體現(xiàn)在View實(shí)現(xiàn)的接口中。
1.2. 發(fā)展歷程
任何一種思想的產(chǎn)生都有其特定的背景,在軟件開發(fā)中也是如此。在軟件復(fù)雜度增長(zhǎng),需求不斷變更的客觀條件下,為了更好的解決這些問題,出現(xiàn)了各種軟件架構(gòu)思想、編程思想以及設(shè)計(jì)模式。(因?yàn)槿说哪芰Σ]有“跟上”機(jī)器,所以才會(huì)出現(xiàn)各種模式、方法、工具等等來(lái)補(bǔ)足人的不足,以最大地透支機(jī)器性能。--Indream Luo)
相信做過客戶端(PC、Android、iOS等)或者前端開發(fā)的童鞋都聽過MVC、MVP、MVVM這些名詞(就算不了解也大致知道有這個(gè)東西吧),這些都是為了解決擁有圖像界面的程序開發(fā)復(fù)雜性而產(chǎn)生的模式。這里說(shuō)的是模式,當(dāng)然有各種各樣的框架方便開發(fā)者在項(xiàng)目中應(yīng)用這種模式,這不是本文重點(diǎn)。
有前輩(Indream Luo)說(shuō)過,架構(gòu)是對(duì)客觀不足的妥協(xié),規(guī)范是對(duì)主觀不足的妥協(xié)。對(duì)此我深表贊同,先不管這些,我們來(lái)看看GUI是怎么和MVX扯上關(guān)系的。
先搞清楚一個(gè)順序,是GUI應(yīng)用程序的出現(xiàn)導(dǎo)致了MVC的產(chǎn)生。GUI應(yīng)用程序提供給用戶可視化的操作界面,這個(gè)界面提供給用戶數(shù)據(jù)和信息。在PC上用戶與界面的交互主要依賴(鍵盤,鼠標(biāo)等。這些操作會(huì)執(zhí)行一些應(yīng)用邏輯,應(yīng)用邏輯(application logic)可能會(huì)觸發(fā)一定的業(yè)務(wù)邏輯(business logic)使應(yīng)用程序數(shù)據(jù)的發(fā)生變更,數(shù)據(jù)的變更自然需要用戶界面的同步變更以提供最準(zhǔn)確的信息。在開發(fā)這類應(yīng)用程序時(shí),為更好的管理應(yīng)用程序的復(fù)雜性,基于職責(zé)分離(Speration of Duties)的思想都會(huì)對(duì)應(yīng)用程序進(jìn)行分層。在開發(fā)GUI應(yīng)用程序的時(shí)候,會(huì)把管理用戶界面的層次稱為View,應(yīng)用程序的數(shù)據(jù)為Model(注意這里的Model指的是Domain Model,這個(gè)應(yīng)用程序?qū)π枰鉀Q的問題的數(shù)據(jù)抽象,不包含應(yīng)用的狀態(tài),可以簡(jiǎn)單理解為對(duì)象)。Model提供數(shù)據(jù)操作的接口,執(zhí)行相應(yīng)的業(yè)務(wù)邏輯。有了View和Model的分層,那么問題就來(lái)了:View如何同步Model的變更,View和Model之間如何粘合在一起。(所謂的MVX中的X都可以歸納為對(duì)這個(gè)問題不同的處理方式)(引自:戴嘉華)。
MVC 的產(chǎn)生
早在上個(gè)世紀(jì)70年代,美國(guó)的施樂公司(Xerox)的工程師研發(fā)了Smalltalk編程語(yǔ)言,并且開始用它編寫圖形界面的應(yīng)用程序。而在Smalltalk-80這個(gè)版本的時(shí)候,一位叫Trygve Reenskaug的工程師設(shè)計(jì)了MVC圖形應(yīng)用程序的架構(gòu)模式,極大地降低了圖形應(yīng)用程序的管理難度。而在四人幫(GoF)的設(shè)計(jì)模式當(dāng)中并沒有把MVC當(dāng)做是設(shè)計(jì)模式,而僅僅是把它看成解決問題的一些類的集合。Smalltalk-80 MVC和GoF描述的MVC是最經(jīng)典的MVC模式。
看到這服務(wù)端的童鞋有話要說(shuō):我們也用MVC,你看Structs、SpringMVC這些都是經(jīng)典的MVC框架。那服務(wù)端的MVC和GUI開發(fā)中的MVC有何不同之處了,請(qǐng)看下面的分析。
MVC Model 2的出現(xiàn)
在Web服務(wù)端開發(fā)的時(shí)候也會(huì)接觸到MVC模式,而這種MVC模式不能嚴(yán)格稱為MVC模式。經(jīng)典的MVC模式只是解決客戶端圖形界面應(yīng)用程序的問題,而對(duì)服務(wù)端無(wú)效。服務(wù)端的MVC模式又自己特定的名字:MVC Model 2,或者叫JSP Model 2,或者直接就是Model 2 。
好吧,說(shuō)了等于沒說(shuō),總之一句話,我們今天所說(shuō)的MVX都有一個(gè)前提,那就是得有GUI,得是來(lái)解決GUI應(yīng)用程序開發(fā)中遇到的問題的。所以,我們只要關(guān)心最經(jīng)典的MVC就可以了,想了解更多的請(qǐng)自行Google。
MVP 的產(chǎn)生
MVP模式是MVC模式的改良。在上個(gè)世紀(jì)90年代,IBM旗下的子公司Taligent在用C/C++開發(fā)一個(gè)叫CommonPoint的圖形界面應(yīng)用系統(tǒng)的時(shí)候提出來(lái)的。
MVVM 的產(chǎn)生
MVVM模式最早是微軟公司提出,并且了大量使用在.NET的WPF和Sliverlight中。2005年微軟工程師John Gossman在自己的博客上首次公布了MVVM模式。
1.3. 為什么需要 MVP
(以下內(nèi)容參考自:MVP在Android平臺(tái)上的應(yīng)用,原文作者konmik,譯者MiJack)
理由1:盡量簡(jiǎn)單
如果你還有讀過這篇文章,請(qǐng)閱讀它:Kiss原則(Keep It Stupid Simple)
大部分的安卓應(yīng)用只使用View-Model結(jié)構(gòu)
程序員現(xiàn)在更多的是和復(fù)雜的View打交道而不是解決業(yè)務(wù)邏輯。
當(dāng)你在應(yīng)用中只使用Model-View時(shí),到最后,你會(huì)發(fā)現(xiàn)“所有的事物都被連接到一起”。
只使用 Model-View
如果這張圖看上去還不是很復(fù)雜,那么請(qǐng)你想象一下以下情況:每一個(gè)View在任意一個(gè)時(shí)刻都有可能出現(xiàn)或者消失。不要忘記View的保存和恢復(fù),在臨時(shí)的view上掛載一個(gè)后臺(tái)任務(wù)。
“所有的事物都被連接到一起”的替代品是一個(gè)萬(wàn)能對(duì)象(god object)。
god object
god object是十分復(fù)雜的,他的每一個(gè)部分都不能重復(fù)利用,無(wú)法輕易的測(cè)試、或者調(diào)試和重構(gòu)。
With MVP
使用MVP
使用 MVP
復(fù)雜的任務(wù)被分成細(xì)小的任務(wù),并且很容易解決。越小的東西,bug越少,越容易debug,更好測(cè)試。在MVP模式下的View層將會(huì)變得簡(jiǎn)單,所以即便是他請(qǐng)求數(shù)據(jù)的時(shí)候也不需要回調(diào)函數(shù)。View邏輯變成十分直接。
理由2:后臺(tái)任務(wù)
當(dāng)你編寫一個(gè)Actviity、Fragment、自定義View的時(shí)候,你會(huì)把所有的和后臺(tái)任務(wù)相關(guān)的方法寫在一個(gè)靜態(tài)類或者外部類中。這樣,你的Task不再和Activity聯(lián)系在一起,這既不會(huì)導(dǎo)致內(nèi)存泄露,也不依賴于Activity的重建。
這里有若干種方法處理后臺(tái)任務(wù),但是它們的可靠性都不及MVP。
1.4. 為什么 MVP 是可行的?
(以下內(nèi)容參考自:MVP在Android平臺(tái)上的應(yīng)用,原文作者konmik,譯者MiJack)
這里有一張表格,用于展示在configuration改變、Activity 重啟、Out-Of-Memory時(shí),不同的應(yīng)用部分會(huì)發(fā)生什么?
不同應(yīng)用部分對(duì)不同場(chǎng)景的響應(yīng)
情景 1: 當(dāng)用戶切換屏幕、更改語(yǔ)言設(shè)置或者鏈接外部的模擬器時(shí),往往意味著設(shè)置改變。 相關(guān)更多請(qǐng)閱讀這里。
情景 2:Activity的重啟發(fā)生在當(dāng)用戶在開發(fā)者選項(xiàng)中選中了“Don’t keep activities”(“中文下為 不保留活動(dòng)”)的復(fù)選框,然后另一個(gè)Activity在最頂上的時(shí)候。
情景 3: 進(jìn)程的重啟發(fā)生在應(yīng)用運(yùn)行在后臺(tái),但是這個(gè)時(shí)候內(nèi)存不夠的情況下。
總結(jié)
現(xiàn)在你可以發(fā)現(xiàn),一個(gè)調(diào)用了setRetainInstance(true)的Fragment也不奏效,我們還是需要保存/恢復(fù)fragment的狀態(tài),所以為簡(jiǎn)化問題,我們暫不考慮上述情況的Fragment。Occam’s razor
場(chǎng)景簡(jiǎn)化
現(xiàn)在,看上去更舒服了,我們只需要寫兩段代碼為了恢復(fù)應(yīng)用:
· 保存/恢復(fù) for Activity, View, Fragment, DialogFragment;
· 重啟后臺(tái)請(qǐng)求由于進(jìn)程重啟
第一個(gè)部分,用Android的API可以實(shí)現(xiàn)。第二個(gè)部分,就是Presenter的作用了。Presenter將會(huì)記住有哪些請(qǐng)求需要執(zhí)行,當(dāng)進(jìn)程在執(zhí)行過程中重啟時(shí),Presenter將會(huì)出現(xiàn)執(zhí)行它們。
1.5. MVP 的優(yōu)缺點(diǎn)
任何事務(wù)都存在兩面性,MVP當(dāng)然也不列外,我們來(lái)看看MVP的優(yōu)缺點(diǎn)。
優(yōu)點(diǎn):
1. 降低耦合度,實(shí)現(xiàn)了Model和View真正的完全分離,可以修改View而不影響Modle
2. 模塊職責(zé)劃分明顯,層次清晰(下面會(huì)介紹Bob大叔的Clean Architecture)
3. 隱藏?cái)?shù)據(jù)
4. Presenter可以復(fù)用,一個(gè)Presenter可以用于多個(gè)View,而不需要更改Presenter的邏輯(當(dāng)然是在View的改動(dòng)不影響業(yè)務(wù)邏輯的前提下)
5. 利于測(cè)試驅(qū)動(dòng)開發(fā)。以前的Android開發(fā)是難以進(jìn)行單元測(cè)試的(雖然很多Android開發(fā)者都沒有寫過測(cè)試用例,但是隨著項(xiàng)目變得越來(lái)越復(fù)雜,沒有測(cè)試是很難保證軟件質(zhì)量的;而且近幾年來(lái)Android上的測(cè)試框架已經(jīng)有了長(zhǎng)足的發(fā)展——開始寫測(cè)試用例吧),在使用MVP的項(xiàng)目中Presenter對(duì)View是通過接口進(jìn)行,在對(duì)Presenter進(jìn)行不依賴UI環(huán)境的單元測(cè)試的時(shí)候。可以通過Mock一個(gè)View對(duì)象,這個(gè)對(duì)象只需要實(shí)現(xiàn)了View的接口即可。然后依賴注入到Presenter中,單元測(cè)試的時(shí)候就可以完整的測(cè)試Presenter應(yīng)用邏輯的正確性。
6. View可以進(jìn)行組件化。在MVP當(dāng)中,View不依賴Model。這樣就可以讓View從特定的業(yè)務(wù)場(chǎng)景中脫離出來(lái),可以說(shuō)View可以做到對(duì)業(yè)務(wù)完全無(wú)知。它只需要提供一系列接口提供給上層操作。這樣就可以做到高度可復(fù)用的View組件。
7. 代碼靈活性
缺點(diǎn):
1. Presenter中除了應(yīng)用邏輯以外,還有大量的View->Model,Model->View的手動(dòng)同步邏輯,造成Presenter比較笨重,維護(hù)起來(lái)會(huì)比較困難。
2. 由于對(duì)視圖的渲染放在了Presenter中,所以視圖和Presenter的交互會(huì)過于頻繁。
3. 如果Presenter過多地渲染了視圖,往往會(huì)使得它與特定的視圖的聯(lián)系過于緊密。一旦視圖需要變更,那么Presenter也需要變更了。
4. 額外的代碼復(fù)雜度及學(xué)習(xí)成本。
1.6. 小結(jié)
在MVP模式里通常包含4個(gè)要素:
(1) View :負(fù)責(zé)繪制UI元素、與用戶進(jìn)行交互(在Android中體現(xiàn)為Activity);
(2) View interface :需要View實(shí)現(xiàn)的接口,View通過View interface與Presenter進(jìn)行交互,降低耦合,方便進(jìn)行單元測(cè)試;
(3) Model :負(fù)責(zé)存儲(chǔ)、檢索、操縱數(shù)據(jù)(有時(shí)也實(shí)現(xiàn)一個(gè)Model interface用來(lái)降低耦合);
(4) Presenter :作為View與Model交互的中間紐帶,處理與用戶交互的負(fù)責(zé)邏輯。
Microsoft對(duì)MVC和MVP的理解
二、MVX 剖析
2.1. M(Model)
模型:表示數(shù)據(jù)模型和業(yè)務(wù)邏輯(business logic)。模型并不總是DataSet,DataTable之類的東西,它代表著一類組件(components)或類(class),這些組件或類可以向外部提供數(shù)據(jù),同時(shí)也能從外部獲取數(shù)據(jù)并將這些數(shù)據(jù)存儲(chǔ)在某個(gè)地方。簡(jiǎn)單的理解,可以把模型想象成“外觀類(facade class)”。譯注:這里的外觀是指“外觀模式”中所說(shuō)的外觀。外觀的一般作用是為一個(gè)復(fù)雜的子系統(tǒng)提供高層次的簡(jiǎn)單易用的訪問接口,可以參看下面的圖來(lái)理解它的原理:
model層主要負(fù)責(zé):
· 從網(wǎng)絡(luò),數(shù)據(jù)庫(kù),文件,傳感器,第三方等數(shù)據(jù)源讀寫數(shù)據(jù)。
· 對(duì)外部的數(shù)據(jù)類型進(jìn)行解析轉(zhuǎn)換為APP內(nèi)部數(shù)據(jù)交由上層處理。
· 對(duì)數(shù)據(jù)的臨時(shí)存儲(chǔ),管理,協(xié)調(diào)上層數(shù)據(jù)請(qǐng)求。
2.2 V(View)
視圖:將數(shù)據(jù)呈現(xiàn)給用戶。一般的視圖都只是包含用戶界面(UI),而不包含界面邏輯。比如,Asp.net中包含控件的頁(yè)面(page)就是一個(gè)視圖。視圖可以從模型中讀取數(shù)據(jù),但是不能修改或更新模型。
view 層主要負(fù)責(zé):
· 提供UI交互
· 在presenter的控制下修改UI。
· 將業(yè)務(wù)事件交由presenter處理。
注意: View層不存儲(chǔ)數(shù)據(jù),不與Model層交互。
在Android中View層一般是Activity、Fragment、View(控件)、ViewGroup(布局等)等。
2.3. X(C-Controller、P-Presenter、VM-ViewModel)
控制器:View捕獲到用戶交互操作后會(huì)直接轉(zhuǎn)發(fā)給Controller,后者完成相應(yīng)的UI邏輯。如果需要涉及業(yè)務(wù)功能的調(diào)用,Controller會(huì)直接調(diào)用Model。在完成UI處理之后,Controller會(huì)根據(jù)需要控制原View或者創(chuàng)建新的View對(duì)用戶交互操作予以響應(yīng)。
層現(xiàn)器:作為View與Model交互的中間紐帶,處理與用戶交互的負(fù)責(zé)邏輯。Presenter包含了根據(jù)用戶在視圖中的行為去更新模型的邏輯。視圖僅僅只是將用戶的行為告知Presenter,而Presenter負(fù)責(zé)從視圖中取得數(shù)據(jù)然后發(fā)送給模型。
視圖模型:binder 所在之處,是 View 的抽象,對(duì)外暴露出公共屬性和命令,它是View的抽象,負(fù)責(zé)View與Model之間信息轉(zhuǎn)換,將View的Command傳送到Model。ViewModel的含義就是 "Model of View",視圖的模型。它的含義包含了領(lǐng)域模型(Domain Model)和視圖的狀態(tài)(State)。可以簡(jiǎn)單把ViewModel理解為頁(yè)面上所顯示內(nèi)容的數(shù)據(jù)抽象,和Domain Model不一樣,ViewModel更適合用來(lái)描述View。
2.4. 小結(jié)
MVC模式、MVP模式和MVVM模式都作為用來(lái)分離UI層與業(yè)務(wù)層的一種開發(fā)模式。這些模式之間的差異可以歸納為對(duì)這個(gè)問題處理的方式的不同。
三、MVX 與三層架構(gòu)
相信不少童鞋和我有過同樣的疑惑:MVX分為了M-V-X三層,那這到底和軟件的三層架構(gòu)有何關(guān)系呢?我們帶著問題繼續(xù)往下閱讀。
3.1. 什么是三層架構(gòu)
三層架構(gòu)是一個(gè)分層式的軟件體系架構(gòu)設(shè)計(jì),它可適用于任何一個(gè)項(xiàng)目。通常意義上的三層架構(gòu)就是將整個(gè)業(yè)務(wù)應(yīng)用劃分為:界面層(User Interface layer)、業(yè)務(wù)邏輯層(Business Logic Layer)、數(shù)據(jù)訪問層(Data access layer)。區(qū)分層次的目的即為了“高內(nèi)聚低耦合”的思想。在軟件體系架構(gòu)設(shè)計(jì)中,分層式結(jié)構(gòu)是最常見,也是最重要的一種結(jié)構(gòu)。微軟推薦的分層式結(jié)構(gòu)一般分為三層,從下至上分別為:數(shù)據(jù)訪問層、業(yè)務(wù)邏輯層(又或稱為領(lǐng)域?qū)樱⒈硎緦印#▍⒖甲裕喊俣劝倏疲?/p>
常見的架構(gòu)有:
· 分層架構(gòu)(如:三層架構(gòu))
· 事件驅(qū)動(dòng)架構(gòu)
· 微內(nèi)核架構(gòu)
· 微服務(wù)架構(gòu)
· 基于空間的架構(gòu)
推薦閱讀《軟件架構(gòu)模式》
3.2. 三層架構(gòu)和 MVX 的關(guān)系
首先,我想說(shuō)三層架構(gòu)(分層架構(gòu))和 MVX 沒有什么關(guān)系,它們不在同一個(gè)層次上(三層是一種架構(gòu)思想,更多的是和事件驅(qū)動(dòng)架構(gòu)、微內(nèi)核架構(gòu)等放在一起討論,而我更喜歡把 MVX 做為模式來(lái)對(duì)待)。
三層是從整個(gè)應(yīng)用程序架構(gòu)的角度來(lái)分為DAL(數(shù)據(jù)訪問層)、BLL(業(yè)務(wù)邏輯層)、WEB層(界面層)各司其職,意在職責(zé)分離;三層是為了解決整個(gè)應(yīng)用程序中各個(gè)業(yè)務(wù)操作過程中不同階段的代碼封裝的問題,為了使程序員更加專注的處理某階段的業(yè)務(wù)邏輯;并且三層只是多層架構(gòu)中的一種情況,完全可以根據(jù)需要分為多層。
MVC 主要是為了解決應(yīng)用程序用戶界面的樣式替換問題,把展示數(shù)據(jù)的 HTML 頁(yè)面盡可能的和業(yè)務(wù)代碼分離。MVC把純凈的界面展示邏輯(用戶界面)獨(dú)立到一些文件中(Views),把一些和用戶交互的程序邏輯(Controller)單獨(dú)放在一些文件中,在 Views 和 Controller 中傳遞數(shù)據(jù)使用一些專門封裝數(shù)據(jù)的實(shí)體對(duì)象,這些對(duì)象,統(tǒng)稱為Models。而在其后出現(xiàn)的 MVP 以及 MVVM 與 MVC 的作用類似,MVX 主要的區(qū)別在于如何解決 M 與 V 之間的連接與更新。
總之一句話,MVX 是一種模式,Spring MVC 以及 ASP.NET MVC 等是一個(gè)基于MVC模式的開發(fā)框架,三層架構(gòu)是一種架構(gòu)。
其次,它們都有一個(gè)表現(xiàn)層,但是這兩者的展現(xiàn)層并不是一樣的。可以這樣看待 MVX 與三層架構(gòu)中的表現(xiàn)層的關(guān)系,MVX 中的 V 和 X 都屬于三層架構(gòu)中的表現(xiàn)層,可以看下圖的示意。
最后,雖然都有提到 Model,但是在 MVX 中沒有把業(yè)務(wù)的邏輯訪問看成兩個(gè)層,這是采用三層架構(gòu)或 MVX 搭建程序最主要的區(qū)別。在三層架構(gòu)中Model 的概念與 MVX 中 Model 的概念是不一樣的,“三層”中典型的Model 層是以實(shí)體類構(gòu)成的,而MVC里,則是由業(yè)務(wù)邏輯與訪問數(shù)據(jù)組成的。
也就是說(shuō),MVX 與三層架構(gòu)說(shuō)的根本不是一回事。在所謂的“三層”中,它要求你將BLL層獨(dú)立出來(lái),它只是告訴你表示層和業(yè)務(wù)邏輯層之間的靜態(tài)關(guān)系。而 MVX 則告訴你在這個(gè)具體的地方如何處理其動(dòng)態(tài)驅(qū)動(dòng)流程,盡管 MVC 仍然粗糙(甚至 MVP、MVVM也是粗糙的),但是已經(jīng)比所謂三層更細(xì)致一些了(三層是架構(gòu)好嗎...)。
MVP和三層架構(gòu)示意圖
四、Android 上 MVP 的幾種實(shí)現(xiàn)
絮絮叨叨說(shuō)了一大堆,終于干貨要來(lái)了。正所謂:Talk is cheap,show me the code.下面會(huì)給出示例代碼,請(qǐng)繼續(xù)閱讀。
在 Android 開發(fā)中討論 MVP、MVVM 最終都離不了Uncle Bob的The Clean Architecture。(請(qǐng)自行閱讀,相信閱讀原文會(huì)有更大的收獲)
下面,我會(huì)嘗試一一細(xì)數(shù) Android 上常見的 MVP 實(shí)現(xiàn)方式(說(shuō)明:并沒有什么排序規(guī)則,只談大家的實(shí)現(xiàn)思路,展示的順序只是為了方便大家的理解和閱讀)。
4.1. 存取用戶信息的 MVP 小 Demo
這其實(shí)是我最先接觸 MVP 時(shí)看到的示例,代碼很少,但是把 MVP 的分層展示的挺清晰。
原文:MVP模式在Android開發(fā)中的應(yīng)用
源碼:GitHub 地址
登錄Demo 界面
項(xiàng)目結(jié)構(gòu)示例
4.2. 天氣查詢的 MVP 小 Demo
現(xiàn)在的 Andorid 開發(fā)怎么能夠離開網(wǎng)絡(luò),來(lái)一個(gè)有網(wǎng)絡(luò)的示例。該天氣查詢 Demo,是通過訪問 Web 服務(wù)獲取地區(qū)的天氣信息(返回為JSON),然后在 Activity 中用 TextView 展示出來(lái)。
原文:Android中的MVP
源碼:GitHub 地址
包結(jié)構(gòu)
項(xiàng)目效果預(yù)覽
4.3. 使用 Activity/Fragment 作為 Presenter 的探索
上面的示例 View 都是 Activity 來(lái)承擔(dān)的,Presenter 是一個(gè)普通的類,前面討論過 Android 在不同場(chǎng)景下會(huì)進(jìn)入不同的生命周期,這將可能導(dǎo)致 Presenter 也隨著其生命周期需要做出響應(yīng)。從這個(gè)角度考慮,有不少開發(fā)者提出了 MVP 實(shí)現(xiàn)的其他思路,接下來(lái)我們要探討的就是使用 Activity/Fragment 作為 Presenter 的一些實(shí)現(xiàn)方案。
4.3.1 一種實(shí)現(xiàn)MVP模式的新思路
其中有使用 Activity 和 Fragment 作為 Presenters 和使用 Adapter作為 Presenter的探討,思路挺有意思,可以去看看。
原文:android-mvp-an-alternate-approach
譯文:一種在android中實(shí)現(xiàn)MVP模式的新思路
源碼:GitHub 地址
4.3.2. TheMVP 介紹
TheMVP使用Activity作為Presenter層來(lái)處理代碼邏輯,通過讓Activity包含一個(gè)ViewDelegate對(duì)象來(lái)間接操作View層對(duì)外提供的方法,從而做到完全解耦視圖層。
原文:用MVP架構(gòu)開發(fā)Android應(yīng)用
源碼:GitHub 地址
TheMVP原理示意
TheMVP項(xiàng)目結(jié)構(gòu)
4.3.3 MVPro 介紹
MVPro的實(shí)現(xiàn)很簡(jiǎn)單,思想和上面兩篇文章(一種在android中實(shí)現(xiàn)MVP模式的新思路和用MVP架構(gòu)開發(fā)Android應(yīng)用)介紹的一樣,都是將Activity和Fragment作為Presenter。Presenter即我們的Activity或者Fragment, View呢?說(shuō)白了就是我們從Activity和Fragment中提取出來(lái)的和View操作相關(guān)的代碼。
源碼:GitHub 地址
MVPro原理示意
4.4. Nucleus 框架
該框架還是值得一看的,作者 Konstantin Mikheev 對(duì)于 MVP 的理解挺有見地。
Nucleus is a simple Android library, which utilizes the Model-View-Presenter pattern to properly connect background tasks with visual parts of an application.
原文:Introduction to Model View Presenter on Android
譯文:介紹ModelViewPresenter在Android中的應(yīng)用
源碼:GitHub 地址
4.5. Beam 框架
該框架的作者對(duì) MVP 的理解的特點(diǎn)如下:
Activity會(huì)在很多情況下被系統(tǒng)重啟:
當(dāng)用戶旋轉(zhuǎn)屏幕
在后臺(tái)時(shí)內(nèi)存不足
改變語(yǔ)言設(shè)置
attache 一個(gè)外部顯示器等。
正確的方式應(yīng)該是:
Presenter與Activity的綁定關(guān)系應(yīng)由靜態(tài)類管理。而不是由Activity管理。當(dāng)Activity意外重啟時(shí)Presenter不應(yīng)重啟。Activity重啟時(shí),Presenter與Activity重新綁定,根據(jù)數(shù)據(jù)恢復(fù)Activity狀態(tài)。
而當(dāng)Activity真正銷毀時(shí)。對(duì)應(yīng)Presenter才應(yīng)該跟隨銷毀。
這也是對(duì) Presenter 管理的一個(gè)思路,可以參考。
原文:Android應(yīng)用中MVP最佳實(shí)踐
源碼:GitHub 地址
Beam MVP
4.6. Mosby 框架
我給這篇關(guān)于Android庫(kù)的博客起的名字靈感來(lái)源于《老爸老媽浪漫史》中的建筑設(shè)計(jì)師Ted Mosby。這個(gè)Mosby庫(kù)可以幫助大家在Android上通過Model-View-Presenter模式做出一個(gè)完善穩(wěn)健、可重復(fù)使用的軟件,還可以借助ViewState輕松實(shí)現(xiàn)屏幕翻轉(zhuǎn)。
這又是一種解決Activity/Fragment生命周期在屏幕翻轉(zhuǎn)等場(chǎng)景下對(duì)Presenter的處理的思路。
原文:Ted Mosby – Software Architect
譯文:MVP框架 – Ted Mosby的軟件架構(gòu)
源碼:GitHub 地址
獲得ViewState支持的Activity的生命周期圖解
獲得ViewState支持的Fragment的生命周期圖解
4.7. Loader 的使用
就像剛才說(shuō)的一樣,關(guān)鍵問題就是在哪里存儲(chǔ)Presenter以及什么時(shí)候銷毀它們。而我們剛剛就看到了Loader的強(qiáng)大之處:由安卓系統(tǒng)框架提供,有單獨(dú)生命周期,會(huì)被自動(dòng)回收且不必在后臺(tái)運(yùn)行。
所以思考一下需求以及Loader的功能,我們可以讓Loader作為Presenter的提供者,而不需要擔(dān)心手機(jī)狀態(tài)改變。
將同步的Loader作為存放Presenter的緩存。
這里的重點(diǎn)就在于同步使用Loader時(shí),我們可以知道在生命周期的哪個(gè)階段Presenter被創(chuàng)建了并且可以工作了。甚至是在Activity/Fragment可見之前。
使用Loader,思路很有新意,關(guān)鍵確實(shí)解決了問題,更關(guān)鍵的是使用的是 Android Framework 提供的功能。
原文:Presenter surviving orientation changes with Loaders
譯文:通過Loader延長(zhǎng)Presenter生命周期
源碼:GitHub 地址
MVP diagram
4.8. Google 官方推薦
大 Boss 總是最后出場(chǎng),對(duì)于 Android 上 MVP 的實(shí)現(xiàn),Google 給也出了一些建議和實(shí)例,趕緊看看去吧。
原文:Android Architecture Blueprints [beta]
源碼:GitHub 地址
Google MVP 示例
4.9. MVP 實(shí)現(xiàn)的完整開源項(xiàng)目
4.9.1. Philm
ChrisBannes的開源項(xiàng)目Philm,其整體架構(gòu)是一套MVP的實(shí)現(xiàn)。這里有一篇分析該項(xiàng)目的文章,可以直接去讀源碼,也可以先看看lightSky是怎么分析的。
Philm 分析:開源項(xiàng)目Philm的MVP架構(gòu)分析
源碼:GitHub 地址
Philm 的總體設(shè)計(jì)
Philm 的類關(guān)系圖
Philm 的基本調(diào)用流程圖
4.9.2. 使用 Beam 開發(fā)的 APP
Fishing空鉤釣魚
Beam 前面已有介紹,感興趣的童鞋可以看看上面兩個(gè)項(xiàng)目。
4.9.3. 干貨集中營(yíng)客戶端
干貨集中營(yíng)有不少的開源實(shí)現(xiàn)都是 MVP 模式的(下面的 App 是官網(wǎng)上列出來(lái)的,具體是否都采用了 MVP 本人沒有一一查閱)。
4.10. 小結(jié)
上述眾多解決方案都集中在 Presenter 實(shí)現(xiàn)的問題上,這主要是由于 Activity、Fragment 的復(fù)雜性導(dǎo)致的,它們有眾多生命周期,它們無(wú)所不能,是否把它們僅僅視作 View 成了爭(zhēng)論的焦點(diǎn)。個(gè)人認(rèn)為從編碼的難易程度和編碼的習(xí)慣來(lái)說(shuō),我贊成把 Activity、Fragment 作為 View 即可,我們可以考慮其他方式來(lái)保證Presenter的生命周期和防止 Presenter 引起內(nèi)存泄漏。其中使用 Loader 的方案就非常優(yōu)雅,下面在本人的示例項(xiàng)目中也會(huì)采用這種方式。
關(guān)于 5 和 6?將在下篇中闡述,示例代碼也會(huì)在下篇中給出。正所謂:Talk is cheap show me the code.
參考:
http://zhuanlan.zhihu.com/tech-frontier/20001838
http://www.cnblogs.com/artech/archive/2012/03/08/2385618.html
http://www.cnblogs.com/artech/archive/2012/03/08/mvc-02.html
http://android.jobbole.com/81153/
http://blog.csdn.net/weizhiai12/article/details/47903883
http://blog.csdn.net/weizhiai12/article/details/47904073
http://android.jobbole.com/82261/
http://android.jobbole.com/82375/
http://blog.csdn.net/wanglei_samrtfish/article/details/7274673
http://www.cnblogs.com/ahwwmb/archive/2012/09/10/2679196.html
http://blog.sina.com.cn/s/blog_9875559401012z7f.html
http://www.oschina.net/question/565065_78760
http://www.admin10000.com/document/535.html
http://www.jcodecraeer.com/a/anzhuokaifa/androidkaifa/2015/0313/2599.html
http://www.jcodecraeer.com/a/anzhuokaifa/androidkaifa/2015/0528/2945.html
http://www.open-open.com/lib/view/open1446377609317.html
https://segmentfault.com/a/1190000003871577
http://www.360doc.com/content/14/0324/12/1355383_363264606.shtml
http://my.oschina.net/aibenben/blog/381274
https://msdn.microsoft.com/en-us/library/ff709839.aspx
http://www.open-open.com/lib/view/open1450008180500.html
http://www.tianmaying.com/tutorial/AndroidMVC
http://www.infoq.com/cn/articles/clean-architecture-model-to-develop-android-application
http://blog.csdn.net/weizaishouex2010/article/details/50461534
http://blog.csdn.net/u012403246/article/details/45715995
http://blog.csdn.net/liuhongwei123888/article/details/50380368
http://www.codeceo.com/article/mvp-android.html
http://www.codeceo.com/article/android-mvp-practice.html
http://www.codeceo.com/article/android-app-mvp.html
http://www.codeceo.com/article/android-mvp-artch.html
http://www.jb51.net/article/78164.htm
http://blog.flyou.ren/?hmsr=toutiao.io&p=179&utm_medium=toutiao.io&utm_source=toutiao.io
http://www.lxweimin.com/p/f6252719b3af#
http://zhuanlan.zhihu.com/tech-frontier/20001838
http://www.wtoutiao.com/p/h01nn2.html
http://q.maiziedu.com/article/8549/
http://www.cnblogs.com/tianzhijiexian/p/4393722.html
http://www.cnblogs.com/indream/p/3602348.html
http://www.mamicode.com/info-detail-519681.html
http://kb.cnblogs.com/page/137392/
http://blog.yongfengzhang.com/cn/blog/write-code-that-is-easy-to-delete-not-easy-to/
http://www.jcodecraeer.com/a/anzhuokaifa/androidkaifa/2015/0214/2480.html
http://www.jcodecraeer.com/a/anzhuokaifa/androidkaifa/2015/1125/3722.html
http://android.jobbole.com/82346/
https://drakeet.me/mvp-and-thinking-in-android