一、MVC模式
1.基本概念
MVC(Model—View—Controller 模型—視圖—控制器)模式,用一種業務邏輯、數據、界面顯示分離的方式組織代碼,在改進和個性化定製界面及用戶交互的同時,無需重新編寫業務邏輯。所有通信都是單向的。
MVC角色定義:
模型層: 針對業務模型建立的數據結構和相關的類,即爲Model。Model是與View無關,而與業務相關的。
視圖層: 一般採用XML文件或Java代碼進行界面的描述,也可以使用Javascript+HTML等方式作爲View層。
控制層: 控制層通常在Activity、Fragment或由它們控制的其他業務類中。
- View 傳送指令到 Controller
- Controller 完成業務邏輯後,要求 Model 改變狀態
- Model 將新的數據發送到 View,用戶得到反饋
Activity並非標準的MVC模式中的Controller,它的首要職責是加載應用的佈局和初始化用戶界面,接受並處理來自用戶的操作請求,進而做出響應。隨着界面及其邏輯複雜度不斷提升,Activity類的職責不斷增加,以至變得龐大臃腫。
2.優缺點
優點:
- 耦合性低
- 重用性高
- 生命週期成本低
- 部署快
- 可維護性高
- 有利軟件工程化管理
缺點:
- 沒有明確的定義
- 不適合小型,中等規模的應用程序
- 增加系統結構和實現的複雜性
- 視圖與控制器間的過於緊密的連接
- 視圖對模型數據的低效率訪問
- 一般高級的界面工具或構造器不支持模式
- 視圖與模型相互耦合,不易開發和維護
在MVC裏,View是可以直接訪問Model的。因此,View裏會包含Model信息,不可避免的還要包括一些業務邏輯。 在MVC模型裏,更關注的Model的不變,而同時有多個對Model的不同顯示及View。所以,在MVC模型裏,Model不依賴於View,但是View是依賴於Model的。不僅如此,因爲有一些業務邏輯在View裏實現了,導致要更改View也是比較困難的,至少那些業務邏輯是無法重用的。
二、MVP模式
1.基本概念
MVP模式將應用分爲三層 :Model、View、Presenter。MVP 模式將 Controller 改名爲 Presenter,同時改變了通信方向。
MVP角色定義:
模型層: 封裝各種數據來源(如網絡、數據庫等),對Presenter層提供簡單易用的接口。
視圖層: 包含界面相關的功能,例如各種Activity、Fragment、View、Adapter等,該層專注於用戶的交互嗎,實現設計師給出的界面、動畫等交互效果。View層一般會持有Presenter層的引用,或可以通過依賴注入(如Dagger)的方式獲得Presenter的實例,並將非UI的路基操作委託給Presenter。
控制層: 充當中間人的角色, 用來隔離View層和Model層,該層是通過從View層剝離控制邏輯部分而形成的,主要負責View層和Model層的控制和交互。
- 各部分之間的通信,都是雙向的。
- View 與 Model 不發生聯繫,都通過 Presenter 傳遞。
- View 非常薄,不部署任何業務邏輯,稱爲"被動視圖"(Passive View),即沒有任何主動性,而 Presenter非常厚,所有邏輯都部署在那裏。
2.優缺點
優點:
- 模型與視圖完全分離,我們可以修改視圖而不影響模型
- 可以更高效地使用模型,因爲所有的交互都發生在一個地方——Presenter內部
- 我們可以將一個Presenter用於多個視圖,而不需要改變Presenter的邏輯。這個特性非常的有用,因爲視圖的變化總是比模型的變化頻繁。
- 三層的交互都是基於接口實現的,有助於對Presenter進行單元測試,同時由於是面向接口編程,只需要事先定義好接口,每一層的事先可以交由不同開發人員並行實現,最終再一起聯調。
缺點:
- 增加代碼類的數量
- 由於進行了三層劃分,函數的調用棧變深了,如果開發人員沒能非常清楚地瞭解哪一層具體該負責哪些功能,那麼可能存在因爲層次職責辨認不清等原因導致不同層之間代碼亂入,從而沒能達到MVP充分解耦各層的目的。
- 由於對視圖的渲染放在了Presenter中,所以視圖和Presenter的交互會過於頻繁。如果Presenter過多地渲染了視圖,往往會使得它與特定的視圖的聯繫過於緊密。一旦視圖需要變更,那麼Presenter也需要變更了。
3.MVP與MVC的區別
MVP 是從經典的模式MVC演變而來,它們的基本思想有相通的地方:Controller/Presenter負責邏輯的處理,Model提供數據,View負責視圖。作爲一種新的模式,MVP與MVC有着一個重大的區別:在MVP中View並不直接使用Model,它們之間的通信是通過中間人Presenter 來進行間接通信的,所有的交互都發生在Presenter內部,Presenter和View以及Model的交互都是通過接口進行的,通常View與Presenter是一對一的,複雜的View可能需要多個Presenter來共同處理。而在MVC中View會從直接Model中讀取數據而不是通過 Controller,而且Controller是基於行爲的,可以被多個View共享。
三、MVVM模式
1.基本概念
MVP中隨着業務邏輯的增加,UI的改變多的情況下,會有非常多的跟UI相關的 Case,這樣就會造成View的接口會很龐大。而MVVM就解決了這個問題,通過雙向綁定的機制,實現數據和UI內容,只要想改其中一方,另一方都能夠及時更新的一種設計理念,這樣就省去了很多在View層中寫很多 Case 的情況,只需要改變數據即可。Angular 和 Ember 都採用這種模式。
相比MVP模式,MVVM將Presenter改爲了ViewModel,同時實現了View和ViewModel的雙向綁定。View層的變化會自動導致ViewModel發生變化,ViewModel的數據變化也會自動實現View的刷新,開發者可以不用直接處理View和數據的更新操作,MVVM框架會自動完成。
MVVM角色定義:
模型層: 負責數據的存儲、讀取網絡數據、操作數據庫數據以及I/O,一般會有一個ViewModel對象來調用獲取這一部分的數據。
視圖層: 僅做和UI相關的工作,我們只在XML、Activity、Fragment寫View層的代碼。View層不做任何業務邏輯、不涉及操作數據、不處理數據、UI和數據嚴格的分開。
控制層: 只做和業務邏輯和業務數據相關的事,不做任何和UI、控件相關的事,不會持有任何控件的引用,更不會通過UI控件的引用去做更新UI的事情。專注於業務的邏輯處理,操作的也都是對數據進行操作,數據源綁定在相應的控件上會自動去更改UI,開發者不需要關心更新UI的事情。
2.優缺點
優點:
- 使得View層和業務邏輯層相互更加獨立,MVP的Presenter層會持有View層引用,而MVVM的ViewModel則沒有,由於這種低耦合,一個ViewModel可以在多個View中使用,可用於頻繁的UI更改
- 使得做UI測試和單元測試更加簡單。
缺點:
- 數據綁定使得 Bug 很難被調試,使得一個位置的 Bug 被快速傳遞到別的位置,要定位原始出問題的地方就變得不那麼容易了。
- 對於簡單的UI界面,使用MVVM是大材小用;對於大型複雜界面,需要保存的狀態數據比較多,ViewModel的創建會比較繁瑣,也會造成內存消耗。
3.DataBinding
MVVM中,ViewModel不會對UI進行更新,而是轉交給Data Binding來完成。它的原理也是使用編譯時註解,生成綁定代碼,監聽數據變化而更新UI。
DataBinding函數庫引入方法:
在build.gradle文件中加入如下配置:
android{
dataBinding{
enabled = ture
}
}
Data Binding表達式:
Data Binding佈局文件以作爲根佈局標籤,裏面又包含data和view兩個標籤,其中data標籤用於實現數據綁定,view標籤是在未使用DataBinding時佈局文件的根標籤。
數據綁定:
編譯生成的綁定類MainActivityBinding是根據佈局文件生成的,類名也是根據其命名的。這個類包含了所有的映射,自動實現數據綁定。數據綁定的用法:
proteected void onCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
MainActivityBinding binding = DataBindingUtil.setContentView(this, R.layout.main_activity);
User user = new User("Test", "User");
binding.setUser(user);
}
也可以通過inflate方式:
MainActivityBinding binding = MainActivityBinding.inflate(getLayoutInflator());
若在ListView或RecyclerView的adapter中使用數據綁定,則可通過:
ListItemBinding binding = ListItemBinding.inflate(LayoutInflater,viewGroup,false);
事件綁定:
在DataBinding的佈局文件中也可進行事件綁定,類似於android:onClick可以綁定Java方法。
使用步驟總結:
- 環境搭建: 在build.gradle中開啓數據綁定。
- 數據: 創建一個數據類。
- 佈局: 創建一個MainActivity對應的佈局文件。
- 綁定: Build -->Make Project,編譯生成一個綁定類。在MainActivity中使用MainActivityBinding完成數據與佈局的綁定。
- 事件監聽: 定義一個事件處理類,在佈局文件中配置事件監聽屬性。在MainActivity的onCreate()方法中創建一個事件處理對象並傳給MainActivityBinding。
- 自動更新: 對數據類型改造,在setter方法中調用notifyPropertyChanged()方法通知屬性修改,進而更新UI。