MVC:
Model: 應(yīng)用數(shù)據(jù)和處理數(shù)據(jù)的邏輯阿宅;一般對應(yīng) JavaBean及一些repository
View: 屏幕上看見的對象就是View對象;一般對應(yīng) Xml 中定義的各類組件
Controller: 邏輯處理單元笼蛛,視圖與模型對象的聯(lián)系紐帶洒放,響應(yīng) View 觸發(fā)的各類事件、管理 Model 與 View 間的數(shù)據(jù)流動(dòng)滨砍;Android 里一般對應(yīng) Activity往湿、Fragment、Service惋戏。
缺點(diǎn):
MVC完整的流程:View 視圖層對應(yīng)xml布局文件领追,所做的事情相當(dāng)有限,布局文件中的事件綁定响逢,數(shù)據(jù)處理都是在acvitity中進(jìn)行绒窑,造成 Acvitity 既像 View 又像 Controller。
什么是 MVP
MVP 與 MVC 最大的區(qū)別就在與將 Model 和 View 通過 Presenter 隔開了舔亭,不再允許其互相直接通信些膨,而所有的消息都是通過 Presenter 這個(gè)中間人來傳遞。而這樣做的目的主要是為了將數(shù)據(jù)和展示劃出更明確的界限钦铺。
并不標(biāo)準(zhǔn)的 MVC 到 MVP 的一個(gè)轉(zhuǎn)變订雾,減少了 Activity 的職責(zé),簡化了 Activity中的代碼职抡,將復(fù)雜的邏輯代碼提取到了 Presenter 中進(jìn)行處理葬燎。與之對應(yīng)的好處就是,耦合度更低,更方便的進(jìn)行測試
各自職責(zé):
- Model:負(fù)責(zé)定義數(shù)據(jù)(解決什么是數(shù)據(jù))
- Presenter:負(fù)責(zé)在Model和View之間谱净,從model里取出數(shù)據(jù)窑邦,格式化后在View上展示(解決如何把數(shù)據(jù)和用戶界面放在一起)。
- View:負(fù)責(zé)擔(dān)任一個(gè)被動(dòng)界面壕探,用于展示數(shù)據(jù)冈钦。(解決如何展示數(shù)據(jù))
Presenter 作為中間者,同時(shí)擁有 View 和 Model 的引用李请,在它們之間起到橋梁作用瞧筛,即 Presenter 會(huì)主動(dòng)和 View 和 Model 進(jìn)行通信。
而Model 和 View 必須是完全隔離的导盅,不允許兩者之間互相通信较幌,保持對彼此的不感知,這樣的好處是徹底將數(shù)據(jù)和展示分離來開白翻,并且可以獨(dú)立的為Model去做測試乍炉。
Model 在三者中是獨(dú)立性最高的,Model不應(yīng)該擁有對View的引用滤馍,而且Model也不需要保存對Presenter的引用岛琼,對于Presenter而言,Model只需要提供接口巢株,等著Presenter來調(diào)用時(shí)返回相應(yīng)數(shù)據(jù)即可,Model 也不應(yīng)該去通知View槐瑞,而是通知 Presenter 來間接的更新View的。
Presenter 和 Model:基于接口來通信阁苞,這樣才能把 Model 和Presenter 的耦合度也降到最低困檩,那么在需要改變 Model 內(nèi)部實(shí)現(xiàn),甚至徹底替換 Model 的時(shí)候猬错,Presenter 則是無需隨之改變的窗看。這樣做帶來的另一個(gè)好處就是你可以通過 Mock 一個(gè) Model 來對 Presenter 以及 View 做模擬測試了,從而提高了可測試性倦炒。
View 和 Presenter:View是需要擁有對Presenter的引用显沈,但僅僅是為了將用戶的操作和事件立即傳遞給Presenter,為了讓 View 和 Presenter 耦合較低逢唤,View也只應(yīng)該通過接口與 Presenter 通信拉讯,從而保證 View 是完全被動(dòng)的,一方面它由用戶的操作觸發(fā)來和Presenter通信鳖藕,另一方面它完全受 Presenter 控制魔慷,唯一需要做的事情就是如何展示數(shù)據(jù)。
三者之間的關(guān)系:
View 和 Model 之間沒有聯(lián)系
View 通過接口向 Presenter 來傳遞用戶操作
Presenter 通過接口和 View/Model 來聯(lián)系著恩。
-
Model 不主動(dòng)和 Presenter 聯(lián)系院尔,被動(dòng)的等著 Presenter 來調(diào)用其接口
View <- 接口 <- Presenter ->接口 -> Model
View -> 接口 -> Presenter <- 接口 <- Model
為什么使用 MVP
在 MVC 中蜻展,XML視圖功能太弱,所以 Activity 既要負(fù)責(zé)視圖的顯示又要加入控制邏輯邀摆,往往需要同時(shí)承擔(dān)和 V 和 C 兩部分職責(zé)纵顾,代碼過于臃腫,不好維護(hù)和擴(kuò)展栋盹,比如說當(dāng)修改數(shù)據(jù)獲取方式的時(shí)候施逾,需要修改的地方太多,而且需要把整個(gè)業(yè)務(wù)邏輯全部看一遍例获,且容易修改錯(cuò)汉额;而當(dāng)使用的MVP模式時(shí),只需要修改 Model 中獲取數(shù)據(jù)的方式榨汤,因?yàn)?Presenter 層拿到的是 Model 的接口,只關(guān)心 Model 層返回的數(shù)據(jù),至于你的數(shù)據(jù)是從網(wǎng)絡(luò)還是數(shù)據(jù)庫還是本地?cái)?shù)據(jù)庫文件獲取的,根本不必關(guān)心蠕搜。 MVP 讓 Activity 成為真正的 View。
優(yōu)點(diǎn):
- 分層更加清晰明確
- 更利于擴(kuò)展和維護(hù)
- 方便對于 Model 進(jìn)行單獨(dú)測試
缺點(diǎn):
- 類比較多
- 由于對視圖的渲染放在了 Presenter 中收壕,所以視圖和Presenter的交互會(huì)過于頻繁讥脐。
- 如果 Presenter 過多地渲染了視圖,往往會(huì)使得它與特定的視圖的聯(lián)系過于緊密啼器。一旦視圖需要變更,那么Presenter也需要變更了
MVVM
ViewModel:
創(chuàng)建關(guān)聯(lián)俱萍,將 Model 和 View 綁定起來,如此之后端壳,我們 Model的更改,通過ViewModel 反饋給 View,從而自動(dòng)刷新界面枪蘑。DataBinding是一個(gè)實(shí)現(xiàn)數(shù)據(jù)和UI綁定的框架损谦,是構(gòu)建MVVM模式的一個(gè)關(guān)鍵的工具,它是支持雙向綁定的岳颇。
ViewModel 只做和業(yè)務(wù)邏輯和業(yè)務(wù)數(shù)據(jù)相關(guān)的事照捡,不做任何和UI、控件相關(guān)的事话侧,ViewModel 層不會(huì)持有任何控件的引用栗精,更不會(huì)在ViewModel中通過UI控件的引用去做更新UI的事情。ViewModel就是專注于業(yè)務(wù)的邏輯處理瞻鹏,操作的也都是對數(shù)據(jù)進(jìn)行操作悲立,這些個(gè)數(shù)據(jù)源綁定在相應(yīng)的控件上會(huì)自動(dòng)去更改UI,開發(fā)者不需要關(guān)心更新UI的事情新博。
總結(jié):
View 層的 Activity 通過 DataBinding 生成 Binding 實(shí)例,把這個(gè)實(shí)例傳遞給ViewModel薪夕,ViewModel 層通過把自身與 Binding 實(shí)例綁定,從而實(shí)現(xiàn) View 中l(wèi)ayout 與 ViewModel 的雙向綁定赫悄。mvvm的缺點(diǎn)是數(shù)據(jù)綁定使得 Bug 很難被調(diào)試原献。你看到界面異常了馏慨,有可能是你 View 的代碼有 Bug,也可能是 Model 的代碼有問題姑隅。數(shù)據(jù)綁定使得一個(gè)位置的 Bug 被快速傳遞到別的位置写隶,要定位原始出問題的地方就變得不那么容易了。
databinding
- gradle 中
dataBinding {
enabled true
}
xml 中
最外層使用 layout 標(biāo)簽粤策,通過 data 標(biāo)簽將該 View 對于的 Model 導(dǎo)入進(jìn)來樟澜,然后在控件中比如 TextView 的 text 屬性就可以和該 Model 的屬性綁定。
支持運(yùn)算符操作叮盘。如三元
支持事件綁定秩贰。Activity 中
ActivityMainTestBinding binding = DataBindingUtil.setContentView(this, R.layout.activity_main_test);
binding.setTest(testModel);
不需要寫 findViewById 和 butterknife,只需要
android:id="@+id/tv"
TextView tv = binding.tv;