MVVM是Model-View-ViewModel的简写,MVVM在MVP的基础上实现了数据视图的绑定(DataBinding),当数据变化时,视图会自动更新;反之,当视图发现变化时,数据也会自动更新。
M: 负责数据的获取
V: 负责视图相关(Activity、layout布局文件)
VM:中间纽带层,负责业务逻辑相关的功能;负责数据的更新,当数据发生变化视图及时更新
MVVM模型图
View和ViewModel使用DataBinding进行通信的需求实现:
1.提供View,ViewModel以及Model三层
2.将布局修改为DataBinding布局
3.View与ViewModel之间通过DataBinding进行通信
4.获取数据并展示在界面上
DataBinding简介
DataBinding是谷歌官方发布的一个实现数据绑定的框架(实现数据与视图的双向绑定),DataBingding可以帮助我们在安卓中更好的实现MVVM模式
DataBinding使用步骤
1.启用DataBinding
2.修改布局文件为DataBinding布局
3.数据绑定
ViewModel和View之间的通信建议使用LiveData + ViewModel的方式
1.LiveData是一个可以被观察的数据持有者,它可以通过添加观察者的方式来让其他组件观察他的变更。
2.LiveData遵从应用程序的生命周期,(如果LiveData的观察者已经是销毁状态,LiveData就不会通知该观察者)
MVVM优点:
1.实现了数据和视图的双向绑定,极大的简化代码
2.LiveData更好的解决MVVM之间的通信问题,并且感知组件的生命周期,有效避免内存泄漏
MVVM缺点:
1.bug难以调试,并且DataBinding目前还存在一些编译的问题
DataBinding的基本使用
布局文件
<?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"
xmlns:tools="http://schemas.android.com/tools">
<data>
<variable
name="account"
type="com.example.imooc.framework_mode.bean.Account" />
<variable
name="activity"
type="com.example.imooc.framework_mode.databinding.DataBindingActivity" />
</data>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"
android:orientation="vertical"
tools:context=".framework_mode.databinding.DataBindingActivity">
<TextView
android:id="@+id/tv_info"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="80dp"
android:text="@{account.name + '|' + account.level}"
tools:text="账号|等级" />
<Button
android:id="@+id/btn_addLevel"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="50dp"
android:onClick="@{activity.onclick}"
android:text="账号等级+1" />
</LinearLayout>
</layout>
实体类
public class Account extends BaseObservable {
/** 账号名称 */
private String name;
/** 账号等级 */
private int level;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Bindable
public int getLevel() {
return level;
}
public void setLevel(int level) {
this.level = level;
notifyPropertyChanged(BR.level);
}
}
Activity
/**
* DataBinding学习
* 双向绑定一般适用于输入框(editText)
*
* @author Administrator
*/
public class DataBindingActivity extends AppCompatActivity {
private ActivityDataBindingBinding binding;
private Account account;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_data_binding);
binding = DataBindingUtil.setContentView(this, R.layout.activity_data_binding);
account = new Account();
account.setName("TEST");
account.setLevel(100);
binding.setAccount(account);
binding.setActivity(this);
}
public void onclick(View view) {
// Toast.makeText(this, "点击了", Toast.LENGTH_LONG).show();
int level = account.getLevel();
account.setLevel(level + 1);
// binding.setAccount(account);
}
}
MVVM框架基本搭建学习
布局文件
<?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"
xmlns:tools="http://schemas.android.com/tools">
<data>
<variable
name="viewModel"
type="com.example.imooc.framework_mode.mvvm.MVVMViewModel" />
</data>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context=".framework_mode.normal.NormalActivity">
<!-- @= :数据和视图双向绑定 -->
<EditText
android:id="@+id/ed_account"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="50dp"
android:text="@={viewModel.userInput}"
android:hint="请输入要查询的账号" />
<Button
android:id="@+id/btn_get_account"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:layout_marginTop="80dp"
android:onClick="@{viewModel.getData}"
android:text="获取账号信息" />
<TextView
android:id="@+id/tv_result"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:layout_marginTop="80dp"
android:text="@{viewModel.result}"
android:hint="账号信息暂未获取" />
</LinearLayout>
</layout>
实体类
public class Account extends BaseObservable {
/** 账号名称 */
private String name;
/** 账号等级 */
private int level;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Bindable
public int getLevel() {
return level;
}
public void setLevel(int level) {
this.level = level;
notifyPropertyChanged(BR.level);
}
}
Model层
/**
* 负责数据的获取
* @author Administrator
*/
public class MVVMModel {
/**
* 模拟获取账号数据
* @param accountName
* @param callback
*/
public void getAccountData(String accountName, MCallback callback) {
Random random = new Random();
boolean isSuccess = random.nextBoolean();
if (isSuccess) {
Account account = new Account();
account.setName(accountName);
account.setLevel(100);
callback.onSuccess(account);
} else {
callback.onFailed();
}
}
}
View层
public class MVVMActivity extends AppCompatActivity {
private ActivityMvvmBinding mvvmBinding;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mvvmBinding = DataBindingUtil.setContentView(this, R.layout.activity_mvvm);
MVVMViewModel mvvmViewModel = new MVVMViewModel(getApplication(), mvvmBinding);
mvvmBinding.setViewModel(mvvmViewModel);
}
}
ViewModel层
public class MVVMViewModel extends BaseObservable {
private MVVMModel mvvmModel;
private ActivityMvvmBinding mvvmBindingl;
private String result;
private String userInput;
/**
* 一般需要传入Application对象,方面在ViewModel中使用Application
* 比如sharedPreferences需要使用
* @param application
*/
public MVVMViewModel(Application application) {
mvvmModel = new MVVMModel();
}
public MVVMViewModel(Application application, ActivityMvvmBinding binding) {
mvvmModel = new MVVMModel();
this.mvvmBindingl = binding;
}
public void getData(View view) {
//使用了DataBinding双向绑定,不需要手动获取输入框的数据 注释掉第40行代码
// String userInput = mvvmBindingl.edAccount.getText().toString();
mvvmModel.getAccountData(userInput, new MCallback() {
@Override
public void onSuccess(Account account) {
String info = account.getName() + "|" + account.getLevel();
setResult(info);
}
@Override
public void onFailed() {
setResult("获取数据失败");
}
});
}
@Bindable
public String getResult() {
return result;
}
public void setResult(String result) {
this.result = result;
notifyPropertyChanged(BR.result);
}
@Bindable
public String getUserInput() {
return userInput;
}
public void setUserInput(String userInput) {
this.userInput = userInput;
notifyPropertyChanged(BR.userInput);
}
}