摘要:我們來瞭解一下MVVM模式與Databinding ,MVVM是一種模式,Databinding 是一種框架。DataBinding是一個實現數據和UI綁定的框架。而ViewModel和View可以通過DataBinding來實現單向綁定和雙向綁定,這套UI和數據之間的動態監聽和動態更新的框架 ...
摘要:我們來瞭解一下MVVM模式與Databinding ,MVVM是一種模式,Databinding 是一種框架。DataBinding是一個實現數據和UI綁定的框架。而ViewModel和View可以通過DataBinding來實現單向綁定和雙向綁定,這套UI和數據之間的動態監聽和動態更新的框架Google已經幫我們做好了。MVVM的思想和MVP類似。在MVVM模式中ViewModel和View是用綁定關係來實現的。
首先我們看一下mvvm中view、model、viewmodel三者是如何分工:
View: 簡單地說不做任何業務邏輯、不涉及處理數據、操作數據,把UI和數據分離。
Model: 實體模型,同時包括Retrofit 的Service ,ViewModel 可以根據Model 獲取一個Bean的Observable<Bean>( RxJava ),然後 做一些數據轉換操作和映射到ViewModel 中的一些欄位,最後把這些欄位綁定到View層上。
ViewModel: 負責完成View於Model間的交互,負責業務邏輯。ViewModel層做的事情剛好和View層相反,ViewModel 只做和業務邏輯和 業務數據相關的事,不做任何和UI、控制項相關的事,ViewModel 層不會持有任何控制項的引用,更不會在ViewModel中通過UI 控制項的引用去做更新UI的事情。ViewModel就是專註於業務的邏輯處理,操作的也都是對數據進行操作,這些個數據源綁定 在相應的控制項上會自動去更改UI。記住:viewModel不做和UI相關的事。
我們在看看它的優勢:
-
低耦合度:在MVVM模式中,數據是獨立於UI的,而ViewModel只負責處理和提供數據,UI想怎麼處理數據都是由UI自己決定的,ViewModel 不涉及任何和UI相關的事也不持有UI控制項的引用,即使控制項改變,ViewModel 幾乎不需要更改任何代碼。
-
更新UI:在MVVM中,我們可以在工作線程中直接修改View Model的數據(只要數據是線程安全的),剩下的就不需要你去關心,數據綁定框架會幫我們搞定。
-
可復用性:一個View Model復用到多個View中,同樣的一份數據,用不同的UI去做展示,對於版本迭代頻繁的UI改動,只需更換View層就行,對於如果想在UI上的做AbTest 更是方便的多。
- 單元測試:View Model裡面是數據和業務邏輯,View中關註的是UI,這樣做測試是很方便的,完全沒有彼此的依賴,不管是UI的單元測試還是業務邏輯的單元測試,都是低耦合的。
view與viewmodel的協作:
Model 是通過Retrofit 去獲取網路數據的,返回的數據是一個Observable<Bean>( RxJava ),Model 層其實做的就是這些。那麼ViewModel 做的就是通過傳參數到Model層獲取到網路數據(資料庫同理)然後把Model的部分數據映射到ViewModel的一些欄位(ObservableField),併在ViewModel 保留這個Model的引用。
三者的關係:
看完上面的圖,相信大家有了瞭解,接下來我們看看在代碼中的實現:
首先在項目里添加依賴:
classpath 'com.android.tools.build:gradle:1.2.3'
classpath 'com.android.databinding:dataBinder:1.0-rc0'
這裡用到 Data Binding,所以在Data Binding的模塊添加插件,在build里添加。
apply plugin: 'com.android.databinding'
接下來我們看一下它的佈局文件:
activity_main.xml
<?xml version="1.0" encoding="utf-8"?> <layout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto"> <data> <variable name="viewModel" type="cn.saiz.mvvmhello.MainViewModel"/> </data> <LinearLayout android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical"> <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="horizontal" android:layout_marginTop="10dp"> <TextView android:layout_width="wrap_content" android:layout_height="match_parent" android:textSize="16sp" android:textColor="@android:color/black" android:gravity="center" android:text="用戶名:"/> <EditText android:layout_width="match_parent" android:layout_height="wrap_content" android:hint="simon" android:text="@={viewModel.userName}" app:addTextChangedListener="@{viewModel.userNameEditTextWatcher}"/> </LinearLayout> <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="horizontal" android:layout_marginTop="10dp"> <TextView android:layout_width="wrap_content" android:layout_height="match_parent" android:textSize="16sp" android:textColor="@android:color/black" android:gravity="center" android:text="密碼:"/> <EditText android:layout_width="match_parent" android:layout_height="wrap_content" android:hint="123456" android:text="@={viewModel.passWord}" app:addTextChangedListener="@{viewModel.passwordEditTextWatcher}"/> </LinearLayout> <Button android:layout_width="match_parent" android:layout_height="wrap_content" android:onClick="@{viewModel.login}" android:text="登錄"/> <Button android:layout_width="match_parent" android:layout_height="wrap_content" android:text="註冊"/> </LinearLayout> </layout>
相信大家看到了,我們的根節點變成了layout,還有一個data節點。
要實現 MVVM 的 ViewModel 就需要把數據與UI進行綁定,data
節點就為此提供了一個橋梁,我們先在data
中聲明一個 variable
,這個變數會為 UI 元素提供數據(例如 TextView 的 android:text),然後在代碼中把”後臺”數據與這個 variable
進行綁定。
大家看一下variable
在 data
節點中聲明一個變數viewModel,這個name可以隨便起。其中 type
屬性就是我們在 Java 文件中定義的ViewModel 類。
在 build.gradle 中添加的那個插件 - com.android.databinding
會根據xml文件的名稱 Generate一個繼承自 ViewDataBinding
的類。
例如,這裡 xml 的文件名叫 activity_main.xml
,那麼生成的類就是 ActivityMainBinding
。
接下來我們綁定variable
@Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); ViewDataBinding binding = DataBindingUtil.setContentView(this, R.layout.activity_main); binding.setVariable(cn.saiz.mvvmhello.BR.viewModel, new MainViewModel(this)); }
綁定之後,我們在佈局里就可以直接使用。看test
是不是很簡單,哈哈。
大家如果對mvvm感興趣,不妨可以深入研究一下,也可以把它跟mvp、mvc做一下對比。相信不久,你會愛上它的。