MVC
View:XML布局文件本涕。
Model:實(shí)體模型(數(shù)據(jù)的獲取、存儲(chǔ)伙窃、數(shù)據(jù)狀態(tài)變化)菩颖。
Controller:對(duì)應(yīng)于Activity,處理數(shù)據(jù)为障、業(yè)務(wù)和UI晦闰。
從上面這個(gè)結(jié)構(gòu)來看,Android本身的設(shè)計(jì)還是符合MVC架構(gòu)的产场,但是Android中純粹作為View的XML視圖功能太弱鹅髓,我們大量處理View的邏輯只能寫在Activity中,這樣Activity就充當(dāng)了View和Controller兩個(gè)角色京景,直接導(dǎo)致Activity中的代碼大爆炸窿冯。相信大多數(shù)Android開發(fā)者都遇到過一個(gè)Acitivty數(shù)以千行的代碼情況吧!所以确徙,更貼切的說法是醒串,這個(gè)MVC結(jié)構(gòu)最終其實(shí)只是一個(gè)Model-View(Activity:View&Controller)的結(jié)構(gòu)执桌。
MVP
View: 對(duì)應(yīng)于Activity和XML,負(fù)責(zé)View的繪制以及與用戶的交互芜赌。
Model: 依然是實(shí)體模型仰挣。
Presenter: 負(fù)責(zé)完成View與Model間的交互和業(yè)務(wù)邏輯。
前面我們說缠沈,Activity充當(dāng)了View和Controller兩個(gè)角色膘壶,MVP就能很好地解決這個(gè)問題,其核心理念是通過一個(gè)抽象的View接口(不是真正的View層)將Presenter與真正的View層進(jìn)行解耦洲愤。Persenter持有該View接口颓芭,對(duì)該接口進(jìn)行操作,而不是直接操作View層柬赐。這樣就可以把視圖操作和業(yè)務(wù)邏輯解耦亡问,從而讓Activity成為真正的View層。
但MVP也存在一些弊端:
Presenter(以下簡稱P)層與View(以下簡稱V)層是通過接口進(jìn)行交互的肛宋,接口粒度不好控制州藕。粒度太小,就會(huì)存在大量接口的情況酝陈,使代碼太過碎版化床玻;粒度太大,解耦效果不好沉帮。同時(shí)對(duì)于UI的輸入和數(shù)據(jù)的變化笨枯,需要手動(dòng)調(diào)用V層或者P層相關(guān)的接口,相對(duì)來說缺乏自動(dòng)性遇西、監(jiān)聽性。如果數(shù)據(jù)的變化能自動(dòng)響應(yīng)到UI严嗜、UI的輸入能自動(dòng)更新到數(shù)據(jù)粱檀,那該多好!
MVP是以UI為驅(qū)動(dòng)的模型漫玄,更新UI都需要保證能獲取到控件的引用茄蚯,同時(shí)更新UI的時(shí)候要考慮當(dāng)前是否是UI線程,也要考慮Activity的生命周期(是否已經(jīng)銷毀等)睦优。
MVP是以UI和事件為驅(qū)動(dòng)的傳統(tǒng)模型渗常,數(shù)據(jù)都是被動(dòng)地通過UI控件做展示,但是由于數(shù)據(jù)的時(shí)變性汗盘,我們更希望數(shù)據(jù)能轉(zhuǎn)被動(dòng)為主動(dòng)皱碘,希望數(shù)據(jù)能更有活性,由數(shù)據(jù)來驅(qū)動(dòng)UI隐孽。
V層與P層還是有一定的耦合度癌椿。一旦V層某個(gè)UI元素更改健蕊,那么對(duì)應(yīng)的接口就必須得改,數(shù)據(jù)如何映射到UI上踢俄、事件監(jiān)聽接口這些都需要轉(zhuǎn)變缩功,牽一發(fā)而動(dòng)全身。如果這一層也能解耦就更好了都办。
復(fù)雜的業(yè)務(wù)同時(shí)也可能會(huì)導(dǎo)致P層太大嫡锌,代碼臃腫的問題依然不能解決。
MVVM
View: 對(duì)應(yīng)于Activity和XML琳钉,負(fù)責(zé)View的繪制以及與用戶交互势木。
Model: 實(shí)體模型。
ViewModel: 負(fù)責(zé)完成View與Model間的交互槽卫,負(fù)責(zé)業(yè)務(wù)邏輯跟压。
MVVM的目標(biāo)和思想與MVP類似,利用數(shù)據(jù)綁定(Data Binding)歼培、依賴屬性(Dependency Property)震蒋、命令(Command)、路由事件(Routed Event)等新特性躲庄,打造了一個(gè)更加靈活高效的架構(gòu)查剖。
數(shù)據(jù)驅(qū)動(dòng)
在常規(guī)的開發(fā)模式中,數(shù)據(jù)變化需要更新UI的時(shí)候噪窘,需要先獲取UI控件的引用笋庄,然后再更新UI。獲取用戶的輸入和操作也需要通過UI控件的引用倔监。在MVVM中直砂,這些都是通過數(shù)據(jù)驅(qū)動(dòng)來自動(dòng)完成的,數(shù)據(jù)變化后會(huì)自動(dòng)更新UI浩习,UI的改變也能自動(dòng)反饋到數(shù)據(jù)層静暂,數(shù)據(jù)成為主導(dǎo)因素。這樣MVVM層在業(yè)務(wù)邏輯處理中只要關(guān)心數(shù)據(jù)谱秽,不需要直接和UI打交道洽蛀,在業(yè)務(wù)處理過程中簡單方便很多。
低耦合度
MVVM模式中疟赊,數(shù)據(jù)是獨(dú)立于UI的郊供。
數(shù)據(jù)和業(yè)務(wù)邏輯處于一個(gè)獨(dú)立的ViewModel中,ViewModel只需要關(guān)注數(shù)據(jù)和業(yè)務(wù)邏輯近哟,不需要和UI或者控件打交道驮审。UI想怎么處理數(shù)據(jù)都由UI自己決定,ViewModel不涉及任何和UI相關(guān)的事,也不持有UI控件的引用头岔。即便是控件改變了(比如:TextView換成EditText)塔拳,ViewModel也幾乎不需要更改任何代碼。它非常完美的解耦了View層和ViewModel峡竣,解決了上面我們所說的MVP的痛點(diǎn)靠抑。
更新UI
在MVVM中,數(shù)據(jù)發(fā)生變化后适掰,我們在工作線程直接修改(在數(shù)據(jù)是線程安全的情況下)ViewModel的數(shù)據(jù)即可颂碧,不用再考慮要切到主線程更新UI了,這些事情相關(guān)框架都幫我們做了类浪。
團(tuán)隊(duì)協(xié)作
MVVM的分工是非常明顯的载城,由于View和ViewModel之間是松散耦合的:一個(gè)是處理業(yè)務(wù)和數(shù)據(jù)、一個(gè)是專門的UI處理费就。所以诉瓦,完全由兩個(gè)人分工來做,一個(gè)做UI(XML和Activity)一個(gè)寫ViewModel力细,效率更高睬澡。
可復(fù)用性
一個(gè)ViewModel可以復(fù)用到多個(gè)View中。同樣的一份數(shù)據(jù)眠蚂,可以提供給不同的UI去做展示煞聪。對(duì)于版本迭代中頻繁的UI改動(dòng),更新或新增一套View即可逝慧。如果想在UI上做A/B Testing昔脯,那MVVM是你不二選擇。
總結(jié)
通過上面的簡述以及模式的對(duì)比笛臣,我們可以發(fā)現(xiàn)MVVM的優(yōu)勢還是非常明顯的云稚。雖然目前Android開發(fā)中可能真正在使用MVVM的很少,但是值得我們?nèi)プ鲆恍┨接懞驼{(diào)研沈堡。