mvvm是使用了databinding + ViewModel + ObservableField + LiveData
第一步:开启databinding
在app gradle中开启databinding
dataBinding {
enabled = true
}
xml布局如下:
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android">
<data>
<variable
name="onClickListener"
type="android.view.View.OnClickListener" />
</data>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<EditText
android:id="@+id/editText"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:ems="10"
android:inputType="textPersonName"
android:text="Name" />
<EditText
android:id="@+id/editText2"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:ems="10"
android:inputType="textPersonName"
android:text="Name" />
<Button
android:id="@+id/button"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:onClick="@{(v) -> onClickListener.onClick(v)}"
android:text="Button" />
</LinearLayout>
</layout>
编译后,会生成根据xml文件名为前缀的类。我的叫ActivityMainBinding,这样我们将该布局跟activity进行绑定。
private ActivityMainBinding mBinding;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mBinding = DataBindingUtil.setContentView(this, R.layout.activity_main);
mBinding.setOnClickListener(this);
}
@Override
public void onClick(View v) {
Toast.makeText(this, "xxx", Toast.LENGTH_LONG).show();
}
}
这样btn的点击事件就完成了,
第二步:使用ObservableField实现数据和ui界面的双向绑定
首先我们需要创建一个bean类,但是其中的变量都是通过ObservableField进行封装。
public class LoginObservableModel {
public ObservableField<String> mPhone = new ObservableField<>();
public ObservableField<String> mCode = new ObservableField<>();
}
然后将该类与xml文件进行绑定
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android">
<data>
<variable
name="onClickListener"
type="android.view.View.OnClickListener" />
<variable
name="loginModel"
type="com.ml.cgzpro.LoginObservableModel" />
</data>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<EditText
android:id="@+id/phone"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:inputType="textPersonName"
android:text="@={loginModel.mPhone}" />
<EditText
android:id="@+id/code"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:inputType="textPersonName"
android:text="@={loginModel.mCode}" />
<Button
android:id="@+id/button"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:onClick="@{(v) -> onClickListener.onClick(v)}"
android:text="Button" />
</LinearLayout>
</layout>
这样通过xml文件,我们就将LoginObservableModel类与xml文件进行了双向绑定,当LoginObservableModel实例中的phone改变的时候xml文件中的手机号就进行修改,当布局中的手机号进行修改实例也会进行修改。
public class MainActivity extends AppCompatActivity implements View.OnClickListener {
private ActivityMainBinding mBinding;
private LoginObservableModel mLoginObservableModel;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mBinding = DataBindingUtil.setContentView(this, R.layout.activity_main);
mBinding.setOnClickListener(this);
//bean双向绑定
mLoginObservableModel = new LoginObservableModel();
mBinding.setLoginModel(mLoginObservableModel);
}
@Override
public void onClick(View v) {
//获取界面code的值
String code = mLoginObservableModel.mCode.get();
//将code值赋给phone
mLoginObservableModel.mPhone.set(code);
}
}
第三步:制作ViewModel层
viewmodel是链接v层和m层的桥梁。从m层获取数据,然后展示给v层。
首先我们需要创建一个viewModel子类。
public class LoginViewModel extends ViewModel {
private final LoginRepository mLoginRepository; //数据仓库
//动态绑定数据
private final MutableLiveData<LoginInfoModel> mLoginLiveData = new MutableLiveData<>();
public LoginViewModel() {
mLoginRepository = new LoginRepository();
}
public void bind(LifecycleOwner owner, Observer observer) {
//监听数据的改变
mLoginLiveData.observe(owner, new Observer<LoginInfoModel>() {
@Override
public void onChanged(@Nullable LoginInfoModel loginInfoModel) {
loginInfoModel.setSuccess(loginInfoModel.getSuccess() + "11'");
//通知监听者数据改变
observer.onChanged(loginInfoModel);
}
});
}
public void login(String phone, String code) {
//通过数据仓库,假装网络请求
mLoginRepository.login(mLoginLiveData, phone, code);
}
}
看下仓库类,里面假装网络请求返回数据。
public class LoginRepository {
public void login(@NonNull MutableLiveData<LoginInfoModel> tag, String phone, String code) {
LoginInfoModel model = new LoginInfoModel();
model.setCode(code);
model.setPhone(phone);
model.setSuccess("成功");
//tag 是数据监听类,假装网络层返回了数据,对数据监听类进行了修改
tag.setValue(model);
}
}
当tag调用类setValue()方法后,接下来我们就可以在modelView层获取通知,通过监听tag。
这样当LoginInfoModel实例改变的时候,通知ViewModel后,去改变LoginObservableModel实例,这样xml布局也就随着改变。
看下activity里的代码:
public class MainActivity extends AppCompatActivity implements View.OnClickListener {
private ActivityMainBinding mBinding;
private LoginObservableModel mLoginObservableModel;
private LoginViewModel mLoginViewModel;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mBinding = DataBindingUtil.setContentView(this, R.layout.activity_main);
mBinding.setOnClickListener(this);
//bean双向绑定
mLoginObservableModel = new LoginObservableModel();
mBinding.setLoginModel(mLoginObservableModel);
mLoginViewModel = new LoginViewModel();
mLoginViewModel.bind(this, new Observer<LoginInfoModel>() {
@Override
public void onChanged(@Nullable LoginInfoModel o) {
Log.i("TAG",o.getSuccess());
}
});
}
@Override
public void onClick(View v) {
//获取界面code的值
String code = mLoginObservableModel.mCode.get();
String phone = mLoginObservableModel.mPhone.get();
mLoginViewModel.login(phone,code);
}
}
总结:
mvvm的整体,和mvp的区别就在于,mvp数据的通知都是通过接口回调的方式,而mvvm是通过观察者模式。
在mvvm中,v和mv中数据通知是通过ObservableField,mv和m中数据通知是通过LiveData。这样一个低耦合的架构就初步完成了。