###1、MVP模式優缺點javascript
在說MVVM以前,簡單回顧一下MVP分層,MVP總共分紅三層:html
MVP模式有其很大的優勢java
可是也有美中不足的部分,MVP模式的缺點以下:react
2.V層與P層仍是有必定的耦合度。一旦V層某個UI元素更改,那麼對應的接口就必須得改,數據如何映射到UI上、事件監聽接口這些都須要轉變,牽一髮而動全身。若是這一層也能解耦就更好了。android
3.複雜的業務同時也可能會致使P層太大,代碼臃腫的問題依然不能解決,這已經不是接口粒度把控的問題了,一旦業務邏輯愈來愈多,View定義的方法愈來愈多,會形成Activity和Fragment實現的方法愈來愈多,依然臃腫。git
###2、MVVM模式github
####2.一、數據的雙向綁定
OK,如今開始介紹MVVM,MVVM模式不是四層,同MVP同樣也是三層,可是我不一樣意MVVM是MVP的升級版,兩者有相同的地方,可是MVP的一些優勢,MVVM也沒法取代,MVVM的三層模型以下:網絡
Model :負責數據實現和邏輯處理,相似MVP。
View : 對應於Activity和XML,負責View的繪製以及與用戶交互,相似MVP。
ViewModel : 建立關聯,將model和view綁定起來。如此以後,咱們model的更改,經過viewmodel反饋給view。(view的xml佈局文件,通過特定的編寫,編譯工具處理後,生成的代碼會接收viewmodel的數據通知消息,自動刷新界面)。架構
能夠看到,MVVM模式的最大亮點是雙向綁定app
單向綁定上,數據的流向是單方面的,只能從代碼流向UI;雙向綁定的數據流向是雙向的,當業務代碼中的數據改變時,UI上的數據可以獲得刷新;當用戶經過UI交互編輯了數據時,數據的變化也能自動的更新到業務代碼中的數據上。對於雙向綁定,恰好可使用DataBinding,DataBinding是一個實現數據和UI綁定的框架,是構建MVVM模式的一個關鍵的工具。因此Android中實現MVVM就方便多了,IOS中還要使用block回調,或者使用reactiveCocoa庫。
####2.二、DataBinding基本用法
#####- Gradle配置
只要在Gradle中的android域裏面,將dataBinding打開就OK了。
#####- 建立實體類
public class User {
private String name;
private String age;
public void onItemClick(View pView) {
Toast.makeText(pView.getContext(), getName(), Toast.LENGTH_SHORT).show();
}
public String getAge() {
return age;
}
public void setAge(String age) {
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public User(String name, String age) {
this.name = name;
this.age = age;
}
}複製代碼
實現綁定的話,佈局編寫和傳統的xml有區別
activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools">
<data>
<variable
name="user"
type="mvvm.wangjing.com.mvvm.User.User" />
</data>
<RelativeLayout
android:id="@+id/activity_main"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="mvvm.wangjing.com.mvvm.MainActivity">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:onClick="@{user.onItemClick}"
android:text="@{`My name is `+ user.name+` I'm `+user.age+` years old `}" />
</RelativeLayout>
</layout>複製代碼
使用DataBinding後,佈局都是以
public class MainActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//setContentView(R.layout.activity_main);
ActivityMainBinding viewDataBinding = DataBindingUtil.setContentView(this, R.layout.activity_main);
User user = new User("Looperjing", "20");
viewDataBinding.setUser(user);
}
}複製代碼
把setContentView(R.layout.activity_main)換成DataBindingUtil.setContentView(this, R.layout.activity_main),返回的是生成的綁定類ActivityMainBinding,而後將user進行綁定。運行效果以下。
public class User extends BaseObservable {
public ObservableField<String> name = new ObservableField<>();
public ObservableField<String> age = new ObservableField<>();
public User(String pName, String pAge) {
name.set(pName);
age.set(pAge);
}
@Bindable
public String getName() {
return name.get();
}
public void setName(String name) {
this.name.set(name);
notifyPropertyChanged(mvvm.wangjing.com.mvvm.BR.name);
}
@Bindable
public String getAge() {
return age.get();
}
public void setAge(String age) {
this.age.set(age);
}
public void onItemClick(View pView) {
Toast.makeText(pView.getContext(), name.get(), Toast.LENGTH_SHORT).show();
setName("June");
}
}複製代碼
用 public ObservableField
對於ObservableField這些字段是能夠稍微作一下分類和包裹的。好比說可能一些字段是綁定到控件的一些Style屬性上(如長度、顏色、大小),對於這類針對View Style的的字段能夠聲明一個ViewStyle類包裹起來,這樣整個代碼邏輯會更清晰一些,否則閱讀性較差。而對於其餘一些字段,好比說title、imageUrl、name這些屬於數據源類型的字段,這些字段也叫數據字段,是和業務數據和邏輯息息相關的,這些字段能夠放在一塊。
上面演示了DataBinding是如何雙向綁定的,這個是實現MVVM模式的中ViewModel的關鍵部分。
####a、View層
view層就是xml和Activity
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools">
<data>
<variable
name="model"
type="mvvm.wangjing.com.mvvm.User.UserViewModel" />
</data>
<RelativeLayout
android:id="@+id/activity_main"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="mvvm.wangjing.com.mvvm.MainActivity">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:onClick="@{model.onItemClick}"
android:text="@{`My name is `+ model.user.name+` I'm `+model.user.age+` years old `}" />
</RelativeLayout>
</layout>複製代碼
請注意 ,此次
<data>
<variable name="model" type="mvvm.wangjing.com.mvvm.User.UserViewModel" /> </data>複製代碼
public class MainActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
final ActivityMainBinding viewDataBinding = DataBindingUtil.setContentView(this, R.layout.activity_main);
UserViewModel userViewModel=new UserViewModel(this,viewDataBinding);
}
}複製代碼
能夠發現,View層作的就是和UI相關的工做,咱們只在XML、Activity和Fragment寫View層的代碼,View層不作和業務相關的事,也就是咱們在Activity不寫業務邏輯和業務數據相關的代碼,更新UI經過數據綁定實現,儘可能在ViewModel裏面作。
####b、ViewModel層
public class UserViewModel {
//注意,這裏都須要定義成public,不然這個字段讀取不到
public User user;
public ActivityMainBinding mainBinding;
public Activity activity;
public UserViewModel(Activity pActivity, ActivityMainBinding pMainBinding) {
this.activity = pActivity;
this.mainBinding = pMainBinding;
mainBinding.setModel(this);
init();
}
private void init() {
user=new User("LooperJing","20");
}
public void onItemClick(View pView) {
Toast.makeText(pView.getContext(), "通知Medel層,異步請求,獲取用戶信息", Toast.LENGTH_SHORT).show();
}
}複製代碼
ViewModel僅僅專一於業務的邏輯處理,只作和業務邏輯和業務數據相關的事,UI相關的事情不要寫在這裏面,ViewModel 層不會持有任何控件的引用,更不會在ViewModel中經過UI控件的引用去作更新UI的事情。可是ViewModel可能會改變數據,因爲數據和UI已經綁定到一塊兒了,因此相應的控件上會自動去更新UI。
####c、Model層
Model層就是職責數據獲取的,網絡請求的邏輯在這裏面寫,相似於MVP。因此我以爲ViewModel層能夠持有一個Model的引用,通知Model獲取數據,同時Model在獲取到數據以後,回調通知ViewModel進行數據更改,進而使UI獲得更新。
總結一下:View層的Activity經過DataBinding生成Binding實例,把這個實例傳遞給ViewModel,ViewModel層經過把自身與Binding實例綁定,從而實現View中layout與ViewModel的雙向綁定。若是不引入ViewModel這一層,還會有一個缺點:一個xml中可能會涉及到多個數據對象,那麼咱們只有把這個多個數據對象都引入進來,xml佈局的清晰程度胡降低,經過這種方法,咱們的layout文件中data標籤中只須要引入ViewModel就能夠了,其它的數據對象統一在ViewModel中一併處理。關於三者的協做關係能夠以下圖表示:
####d、MVVM的問題
第一點:數據綁定使得 Bug 很難被調試。你看到界面異常了,有多是你 View 的代碼有 Bug,也多是 Model 的代碼有問題。數據綁定使得一個位置的 Bug 被快速傳遞到別的位置,要定位原始出問題的地方就變得不那麼容易了。
第二點:對於過大的項目,數據綁定須要花費更多的內存。
對於MVVM的理解,發現網絡上,你們在總體上的理解是差很少的,可是細節上有一些不同的地方,好比MVVM的業務邏輯分工不是很明確,有些人會在ViewModel寫,有的會在Moldel中寫,甚至還有一些反對派戳我,認爲MVVM違背的JAVA的分層設計思想,我認爲無論什麼架構設計模塊化,分層思想是基礎,因此這個基本的原則咱們要遵照,對一些新的架構模式,抱着一個客觀的態度去學學習老是能夠提升本身的設計水平。
Please accept mybest wishes for your happiness and success !
推薦閱讀:
Android架構設計---MVP模式第(一)篇之基本認實
Android架構設計---MVP模式第(二)篇,如何減小類爆炸
參考:
zhuanlan.zhihu.com/p/23772285?…