目錄
一、MVC(Model-View-Controller)
二、 MVP(Model-View-Presenter)
三. MVVM(Model-View-ViewModel)
四. MVI(Model-View-Intent)
五.MVI簡單實現
先簡單了解一下MVC、MVP和MVVM。
一、MVC(Model-View-Controller)
模型-視圖-控制器
MVC的目的就是為了M和V代碼分離,降低耦合性。
Model:數據來源,網絡請求數據和數據庫數據。
View:對應xml布局文件和動態的布局部分。
Controller:邏輯控制部分。主要起到協調M層和V層的關系,起承上啟下的作用。
優點:
一定程度上實現了代碼分離,降低代碼的耦合性。
缺點:
1.Controller和View層難以完全解耦,而且隨著業務邏輯增多
2.Controller會變的越來越臃腫。在Android中Activity充當Controller的角色,后面Activity會變成GadActivity。
3. M層和V層還有交互,沒有做到完全分離。
二、 MVP(Model-View-Presenter)
模型-視圖-提供者
MVP是在MVC的基礎上發展過來的,實現了M層和V層的完全分離,進一步代碼解耦。
Model:數據來源,網絡請求數據和數據庫數據。
View:對應xml布局文件和動態的布局部分。對應Activity。
Presenter:邏輯控制部分。通過接口連接M層和V層。
優點:
1.V層對應Activity,只負責UI的展示和P層直接通信,和M層沒有任何交互。
2.V層沒有和M層有交互,可以抽成單獨的組件,方便復用。
3.代碼結構清晰,P層可以用于多個視圖,而不需要改變P層的邏輯。
4.V層和M層完全分離,方便協同工作,只需要專注做視圖或者邏輯控制部分,不用關系對方的邏輯。比如負責邏輯控制部分不用等設計出圖,就可以直接寫代碼,并進行單元測試。
5.代碼復用率高,方便單元測試。
缺點:
1.M層和V層都需要和P層進行通許,會導致P層代碼很復雜,而且都是通過接口通訊,如果一個P層用于多個Activity,所有Activity都要實現全部都接口,無論能不能用得到。修改P層接口,往往會涉及到很多個界面,很麻煩。
2.P層和V層通過接口通訊,會持有View的引用,容易造成內存泄露。
3.隨著業務增多,P層即使只對應一個視圖,接口也會越來越多。
三. MVVM(Model-View-ViewModel)
模型-視圖-視圖模型
MVVM在MVP的基礎上進一步解耦,VM層不在持有View的引用。
引入響應式編程、Lifecycle生命周期感知、LiveData數據存儲、DataBinding數據綁定概念。配合Goole提供的Jetpack組件能節省很多代碼。
Model:數據來源,網絡請求數據和數據庫數據。
View:對應xml布局文件和動態的布局部分。對應Activity。向比較MVP這里的View是通過DataBinding來進行雙向綁定數據。
ViewModel:邏輯控制部分。作為橋梁,通知M層處理數據,并將結果回調到V層處理UI。Activity持有ViewModel引用,ViewModel不持有View的引用。
優點:
1.進一步解耦,ViewModel不持有View的引用,當V層改遍,只要V層綁定的數據不變,ViewModel就不需要修改。
2.不需要寫很多樣板代碼,省略findViewById(),Activity變得很簡介。
3.通過DataBinding實現View和Model的實時改變,一方改變就會同步到對方。
缺點:
1.DataBinding雙向綁定采用異步更新數據,對ListView這樣的列表,效率比較低。而且在實際開發中,設計出的Ui效果比較復雜,數據綁定不能完全實現,往往只使用到DataBinding一半的功能,數據更新部分還是手動實現。
2.DataBinding會自動生成大量的代碼和屬性字段。
3.復雜的頁面要定義多個LiveData,并且都要暴露為不可變的LiveData。
4.LiveData是粘性事件,數據倒灌等問題。解決方法:使用第三方 UnPeekLiveData
四. MVI(Model-View-Intent)
模型-視圖-意圖
出現的目的是為了解決MVVM中雙向綁定數據的不足。把雙向綁定變成單向數據流。使用Flow代替LiveData存儲數據。
Model:這里的Model不是其他框架中的Model層,在MVI框架中表示存儲UI的狀態。
View:在MVI中View層主要是接口,負責相應UI的狀態。
Intent:在MVI中Intent(和Android中的Intent不是同一個)主要負責傳遞UI狀態。使用sealed關鍵字,形成一個封閉類,類似枚舉。主要用于V層通知ViewModel處理數據。
State:和Intent一樣是一個封閉類,主要用于ViewModel回調數據修改UI。
優點:
1.UI的所有變化來自State,所以只需聚焦State,架構更簡單、易于調試
2.數據單向流動,很容易對狀態變化進行跟蹤和回溯
3.State實例都是不可變的,確保線程安全
4.UI只是反應State的變化,沒有額外邏輯,可以被輕松替換或復用
缺點:
1.所有的操作最終都會轉換成State,所以當復雜頁面的State容易膨脹
2.State是不變的,每當State需要更新時都要創建新對象替代老對象,這會帶來一定內存開銷
五、總結
mvc:activity即是v也是c,代碼臃腫
mvp:接口太多,p層容易內存泄漏
mvvm:databinding生成的代碼態度,livedata數據倒灌/粘性
mvi:復雜頁面,state膨脹
非常小的項目用MVC
六.MVI簡單實現
1.MVI
mvi的改動在于將View和ViewModel之間的多數據流改為基于ViewState的單數據流。
MVI分為四個部分:
- View: Activity 和xml文件,與其他模式中的View的概念相同。
- Intent: 定義數據操作,將數據傳到Model的唯一來源。
- ViewModel: 存儲視圖狀態,負責處理表現邏輯,并將ViewState設置給可觀察數據容器
- ViewState: 一個數據類,包含頁面狀態和對應的數據。
2.MVI特點
唯一可信源:數據只有一個來源(ViewModel),與MVVM思想相同
單向數據流:狀態向下流動,事件向上流動。
響應式:ViewState包含頁面當前狀態和數據,View通過訂閱
ViewState就可以完成頁面刷新。相比于 MVVM 是新的特性。
3.單向數據流
界面變化是數據流的末端,界面消費上游產生的數據,并隨上游數據的變化進行刷新。
狀態向下流動,事件向上流動的這種模式稱為單向數據流
MVI強調數據的單向流動,主要分為幾步:
- 用戶操作以Intent的形式通知Model.
- Model基于Intent更新State
- View接收到State變化刷新UI
數據永遠在一個環形結構中單向流動,不能反向流動。
4.缺點:
- State 膨脹: 所有視圖變化都轉換為 ViewState,還需要管理不同狀態下對應的數據。實踐中應該根據狀態之間的關聯程度來決定使用單流還是多流;
- 內存開銷: ViewState 是不可變類,狀態變更時需要創建新的對象,存在一定內存開銷;
- 局部刷新: View 根據 ViewState 響應,不易實現局部 Diff 刷新,可以使用 Flow#distinctUntilChanged() 來刷新來減少不必要的刷新。
?