MVVM 与 MVP 基本类似,将presenter 换为 ViewModel, 用 data-binding 连接 View 和 ViewModel,进行双向交互。当 View 修改时,会反映到 ViewModel,ViewModel 有变化,会影响到 View,它们之间互相影响,而不像 MVP ,只是 View 被动的接受 Presenter 的调用。
关于 data-binding的知识,官网发布了 Data Binding Library 库。
首先在 build.gradle中:
android {
...
dataBinding{
enabled = true
}
}
Xml 需要引入 data 标签,让 ViewModel 可以和 View 进行双向交互。
<layout
xmlns:android="http://schemas.android.com/apk/res/android">
<data>
<variable name="viewModel" type="com.example.mvvm.ViewModel"/>
</data>
<RelativeLayout
..
<EditText
android:id="@+id/ex_name"
..
android:hint="姓名"/>
<Button
android:id="@+id/btn"
..
android:onClick="@{viewModel.onClick}"//1
android:text="查询"/>
<TextView
android:id="@+id/tv_result"
..
android:text=""/>
</RelativeLayout>
</layout>
ViewModel
public class ViewModel implements OnSearchListener{
private static final String TAG = "ViewModel";
private ActivityMainBinding mActivityMainBinding;
private User mUser;
public ViewModel(ActivityMainBinding activityMainBinding) {
mActivityMainBinding = activityMainBinding;
mUser = new User(this);
// mActivityMainBinding.setModel(mUser);
}
/**
* 在 XML 中Button 的点击方法
* @param view
*/
public void onClick(View view) {
Log.d(TAG, "onSearch: ");
String name = mActivityMainBinding.exName.getText().toString();
if(!TextUtils.isEmpty(name)){
mUser.getResult(name);
}
}
@Override
public void onSuccess(String name) {
mUser.setName(name);
mActivityMainBinding.tvResult.setText(mUser.getName());
}
@Override
public void onError() {
// mUser.setName("失败");
mActivityMainBinding.tvResult.setText("失败");
}
}
Activity
ActivityMainBinding binding = DataBindingUtil.setContentView(this,R.layout.activity_main);
//绑定 viewModel
binding.setViewModel(new ViewModel(binding));
当 xml 完成后,会生成 xml 文件名 + Binding 的类。
比如:activity_main–> ActivityMainBinding.
这个类可以将 data 标签中类 和 xml 控件绑定在一起。
ViewModel
public class ViewModel implements OnSearchListener{
private static final String TAG = "ViewModel";
private ActivityMainBinding mActivityMainBinding;
private User mUser;
public ViewModel(ActivityMainBinding activityMainBinding) {
mActivityMainBinding = activityMainBinding;
mUser = new User(this);
// mActivityMainBinding.setModel(mUser);
}
/**
* 在 XML 中Button 的点击方法
* @param view
*/
public void onClick(View view) {
Log.d(TAG, "onSearch: ");
String name = mActivityMainBinding.exName.getText().toString();
if(!TextUtils.isEmpty(name)){
mUser.getResult(name);
}
}
@Override
public void onSuccess(String name) {
mUser.setName(name);
mActivityMainBinding.tvResult.setText(mUser.getName());
}
@Override
public void onError() {
// mUser.setName("失败");
mActivityMainBinding.tvResult.setText("失败");
}
}
Model 做匹配工作。
然而 data-binding 的双向交互还没有体现出来,就像 RecyclerView 和 Adapter。当数据变化时,提醒 视图更新。
提醒更新方式有两种:在Bean 类中操作
1:需要在 data 标签中声明,在控件中引用属性。
<data>
..
<variable name="model" type="com.example.mvvm.User"/>
</data>
..
<TextView
...
android:text="@{model.name}"/>
2.进行绑定
...
mActivityMainBinding.setModel(mUser);
3.添加响应
(1)需要继承 BaseObservable,在get方法添加注解 @Bindable,在对应的 set 方法中,notifyPropertyChanged(BR.‘属性名’);这样调用用 set 方法时,View 中的数据就会自动更新。
public class User extends BaseObservable{
private static final String TAG = "ViewModel";
private String name = "fdsf";
private OnSearchListener mOnSearchListener;
public User(OnSearchListener onSearchListener) {
mOnSearchListener = onSearchListener;
}
@Bindable
public String getName() {
return name;
}
public void setName(String nsame) {
this.name = nsame;
notifyPropertyChanged(BR.name);
}
public void getResult(String name){
this.name= name;
if(name.equals(this.name)){
mOnSearchListener.onSuccess(name);
}else{
mOnSearchListener.onError();
}
}
(2)使用 Observablexxx 包装属性
使用时:需要 属性名.set(),属性名.get()
public ObservableField name = new ObservableField<>();
this.name.set(name);
String s = this.name.get();
“`
这是一些基本的知识点,但还有一些疑惑,在添加自动更新后,Model 与 View 之间也有直接联系,这样不符合 MVVP 模式的设计原则。
源码