MVC模式
MVC模式的结构分为三部分,实体层Model,视图层View和控制层Controller。
工作原理:当用户触发事件,View层会发出指令到Controller层,由Controller层去通知Model层更新数据,Model层更新完数据后直接显示在View层上。
在Android工程中,View层对应xml布局文件,Controller层对应Activity,Model层对应各类Java bean和API等。
xml作为View层,控制能力太弱,比如动态改变TextView的字号、Progress的显示等,无法再xml中实现,只能在Activity中做,这就造成了Activity既是view层,又是Controller层,这样一来V和C就耦合在一起了,如果业务调整,可维护性与可测试性就降低了。
View和model可以直接交互,这就意味着两层之间存在耦合,当程序业务调整或代码量上升时,开发、测试、维护的难度都会上升。
MVP模式
在view和model之间新增presenter作为沟通的桥梁,presenter从model获取数据后,更新view的展示,使得view和model之间没有耦合,也将业务逻辑从view上抽离出来。
presenter处理业务逻辑并更新view,Activity只提供基础的操作view的能力,二者互相独立,view与业务分离。
当我们把业务逻辑抽取到presenter后,Activity基本上只剩下一些view的逻辑,真正实现了减负,变成了一个相对纯净的view。当我们需要修改view的逻辑时,就去找Activity,需要修改数据逻辑时,就去找Model,修改业务逻辑时就去找presenter,每个模块职责分明。
MVP+VM模式
通过DataBinding实现model到view的单向绑定,使用viewModel作为model和view 的适配层,减少view与model之间因频繁交互而产生的冗余代码。
在标签中引入data=User。当model变化时,通过data将数据映射到view上。当Button产生点击事件时交由presenter响应并处理。使用Databinding以后,开发流程上省略了findView,setView的过程,在写xml的时候就可以直接将model进行关联及映射。
如图:用户操作view,触发事件响应,通过presenter中转,传递给model进行数据处理,获取新数据后处理业务逻辑,并适配成不同状态的viewModel展示策略,view根据不同的viewModel进行更新。
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android">
<data>
<variable
name="user"
type="com.cardioray.testdatabinding.UserModel"/>
<variable
name="presenter"
type="com.cardioray.testdatabinding.Presenter"/>
</data>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
android:orientation="vertical">
<TextView
android:layout_margin="10dp"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@{user.firstName}"/>
<TextView
android:layout_margin="10dp"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@{user.lastName}"/>
<Button
android:layout_margin="10dp"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Hello World!"
android:onClick="@{() -> presenter.onClickTest()}"/>
</LinearLayout>
</layout>
View层的Model类
public class UserMoel extends BaseObservable {
private String firstName;
public ObservableField<String> lastName = new ObservableField<>();
public UserModel(String firstName, String lastName) {
this.firstName = firstName;
this.lastName.set(lastName);
}
@Bindable
public String getFirstName() {
return firstName;
}
public void setFirstName(String firstName) {
this.firstName = firstName;
notifyPropertyChanged(com.cardioray.testdatabinding.BR.firstName);
}
}
MainPresenter不再与view频繁的交互,仅仅是作为view和model的连接器,主干逻辑更为清晰
public class MainPresenter implements IMainPresenter {
private IMainView mIMainView;
private UserModel mModel;
public MainPresenter(IMainView iMainView) {
mIMainView = iMainView;
}
// 请求数据
@Override
public void requestData() {
mServerApi.getDepositInfo();
}
// 获取数据,通知view更新
@Override
public void onLoadDepositSuccess(UserModel model) {
mModel = model;
mIMainView.updateData(model);
}
// 接收并处理view的点击事件
@Override
public void onButtonClickAction(View v) {
}
}
MainActivity中不再需要fingViewById,也不用定义Textview,Button的成员变量,全部交由DataBinding进行处理,相较MVP的实现,MainActivity进一步简化
public class MainActivity extends AppCompatActivity implements IMainView {
private IMainPresenter mPresenter;
private ActivityMainBinding mBinding;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mBinding = DataBindingUtil.setContentView(this, R.layout.activity_main);
mPresenter = new MainPresenter(this);
mBinding.setPresenter(mPresenter);
// 初始化页面数据
mPresenter.requestData();
}
// 更新数据绑定
@Override
public void updateData(UserModel model) {
mBinding.setData(model);
}
@Override
public void showToast(String text) {
Toast.makeText(this, text, Toast.LENGTH_SHORT).show();
}
}
总结
从mvc到mvpvm,项目中类虽然变多了,不过模块之间职责更加明确清晰。大部分情况,使用mvp结合databinding就可以较好的对view和model进行解耦,且代码冗余较少。
在MVC中发现Activity过重,所以引入MVP,Presenter作为View和Model的中转,达到解耦的目的。后来发现Activity提供view能力时冗余代码过多,所以引入viewModel(DataBinding),将xml与model进一步解耦,同时减轻model负担,不过此时并不算是mvvm,本质上在mvp的基础上,引入vm,因此presenter的中转作用还在,所以才演变成了现在的mvpvm。