Android开发中的MVC_MVP_MVVM
为什么要学习MVC
需求(查询用户账号信息):
用户输入账号,点击按钮可进行查询账号信息,如果查询数据成功,则将数据展示在界面上;如果查询数据失败,则在界面上提示获取数据失败。
不实用框架实现需求
创建一个Activity,实现它的所有功能(获取用户输入信息,展示获取信息成功界面,展示获取信息失败界面,查询用户数据,业务逻辑)。
public class MainActivity extends AppCompatActivity implements View.OnClickListener {
private EditText edittext;
private Button button;
private TextView text;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main2);
init();
}
private void init() {
edittext = findViewById(R.id.edittext);
button = findViewById(R.id.button);
button.setOnClickListener(this);
text = findViewById(R.id.text);
}
@Override
public void onClick(View v) {
String userInput = getUserInput();
getAccountData(userInput, new MCallBack() {
@Override
public void onSuccess(Account account) {
showSuccessPage(account);
}
@Override
public void onFail() {
showFailPage();
}
});
}
//获取用户输入信息
private String getUserInput() {
return edittext.getText().toString().trim();
}
//展示获取信息成功界面
private void showSuccessPage(Account account) {
text.setText("用户账号:" + account.getName() + "|" + "用户等级:" + account.getLevel());
}
//展示获取信息失败界面
private void showFailPage() {
text.setText("获取数据失败");
}
//查询用户数据
private void getAccountData(String accountName, MCallBack mCallBack) {
Random random = new Random();
boolean isSuccess = random.nextBoolean();
if (isSuccess) {
Account account = new Account();
account.setName(accountName);
account.setLevel(100);
mCallBack.onSuccess(account);
} else {
mCallBack.onFail();
}
}
}
由上述代码可以发现,MainActivity承载了太多的功能,既要实现方法,又要承担逻辑,这样当以后功能越来越多的时候,这个界面的代码就会越来越多,越来越臃肿。
MVC模型简介
MVC的全名是Model View Controller,即模型(Model)-视图(View)-控制器(Controller)。
Controller:Activity,Fragment
View:layout,View控件
Controller:数据处理(网络请求,SQL等)
WX20191121-161628.png
使用MVC实现需求
MVCActivity(C层):业务逻辑处理,获取用户输入,展示成功界面,展示失败界面
MVCModel(M层):查询账号数据
View(V层):layout
1.将数据的获取和界面的展示分离(将查询账号数据从Activity中分离到Model中即可)
2.解决各层之间的通信问题(Activity通知Model获取数据,Model通知Activity更新界面)
public class MVCActivity extends AppCompatActivity implements View.OnClickListener {
private EditText edittext;
private Button button;
private TextView text;
private MVCModel mvcModel;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main2);
init();
}
private void init() {
edittext = findViewById(R.id.edittext);
button = findViewById(R.id.button);
button.setOnClickListener(this);
text = findViewById(R.id.text);
mvcModel = new MVCModel();
}
@Override
public void onClick(View v) {
mvcModel.getAccountData(getUserInput(), new MCallBack() {
@Override
public void onSuccess(Account account) {
showSuccessPage(account);
}
@Override
public void onFail() {
showFailPage();
}
});
}
//获取用户输入信息
private String getUserInput() {
return edittext.getText().toString().trim();
}
//展示获取信息成功界面
private void showSuccessPage(Account account) {
text.setText("用户账号:" + account.getName() + "|" + "用户等级:" + account.getLevel());
}
//展示获取信息失败界面
private void showFailPage() {
text.setText("获取数据失败");
}
}
public class MVCModel {
//查询用户数据
public void getAccountData(String accountName, MCallBack mCallBack) {
Random random = new Random();
boolean isSuccess = random.nextBoolean();
if (isSuccess) {
Account account = new Account();
account.setName(accountName);
account.setLevel(100);
mCallBack.onSuccess(account);
} else {
mCallBack.onFail();
}
}
}
MVC优缺点
优点:一定程度上实现了Model与View的分离,降低了代码的耦合性。
缺点:Controller与View难以完全解耦,并且随着项目复杂度的提升,因为Controller还承担部分业务逻辑,所以Controller将越来越臃肿。
MVP模型简介
MVP即Model_View_Presenter模型
WX20191121-161412.png
MVP与MVC的差别
1.Model与View不再直接进行通信,而是通过中间层Presenter来实现。
- Activity的功能被简化,不再充当控制器,主要负责View层面的工作。
MVP代码实战
WX20191121-162447.png使用MVP实现需求
- MVPActivity负责提供View层面的功能(采用实现接口的方式)
2.MVPModel负责提供数据方面的功能
3.Model与View不再直接通信,通过Presenter来实现
public class MVPActivity extends AppCompatActivity implements View.OnClickListener, IMVPView {
private EditText edittext;
private Button button;
private TextView text;
private MVPPresenter mvpPresenter;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main2);
init();
}
private void init() {
edittext = findViewById(R.id.edittext);
button = findViewById(R.id.button);
button.setOnClickListener(this);
text = findViewById(R.id.text);
mvpPresenter = new MVPPresenter(this);
}
@Override
public void onClick(View v) {
mvpPresenter.getData(getUserInput());
}
@Override
public String getUserInput() {
return edittext.getText().toString().trim();
}
@Override
public void showSuccessPage(Account account) {
text.setText("用户账号:" + account.getName() + "|" + "用户等级:" + account.getLevel());
}
@Override
public void showFailPage() {
text.setText("获取数据失败");
}
}
public interface IMVPView {
String getUserInput();
void showSuccessPage(Account account);
void showFailPage();
}
public class MVPModel {
//查询用户数据
public void getAccountData(String accountName, MCallBack mCallBack) {
Random random = new Random();
boolean isSuccess = random.nextBoolean();
if (isSuccess) {
Account account = new Account();
account.setName(accountName);
account.setLevel(100);
mCallBack.onSuccess(account);
} else {
mCallBack.onFail();
}
}
}
public class MVPPresenter {
private IMVPView imvpView;
private MVPModel mvpModel;
public MVPPresenter(IMVPView imvpView) {
this.imvpView = imvpView;
mvpModel = new MVPModel();
}
public void getData(String accountName) {
mvpModel.getAccountData(accountName, new MCallBack() {
@Override
public void onSuccess(Account account) {
imvpView.showSuccessPage(account);
}
@Override
public void onFail() {
imvpView.showFailPage();
}
});
}
}
MVP优缺点
优点:解决了MVC中Controller与View过度耦合的缺点,职责划分明显,更加易于维护。
缺点:接口数量多,项目复杂度升高。随着项目复杂度的提升,Presenter层将越来越臃肿。
使用MVP的建议
1.接口规范化(封装父类接口以减少接口的使用量)
2.使用第三方插件自动生成MVP代码
3.对于一些简单的界面,可以选择不使用框架
4.根据项目复杂程度,部分模块可以选择不使用接口
MVVM模型简介
WX20191121-165818.pngMVVM是Model-View-ViewModel的简写,MVVM在MVP的基础上实现了数据视图的绑定(DataBinding),当数据变化时,视图会自动更新;反之,当视图发生变化时,数据也会自动更新。
1.减少了接口数量
2.告别繁琐findViewById操作
DataBinding是什么
DataBinding是谷歌官方发布的一个实现数据绑定的框架(实现数据与视图双向绑定),DataBinding可以帮助我们在安卓中更好的实现MVVM模式。
DataBinding使用步骤
1.启用DataBinding
2.修改布局文件为DataBinding布局
3.数据绑定
使用MVVM实现需求
WX20191126-155005.png1.提供View,ViewModel以及Model三层
2.将布局修改为DataBinding布局
- View与ViewModel之间通过DataBinding进行通信
- 获取数据并展示在界面上
public class MVVMActivity extends AppCompatActivity {
private MVVMViewModel mvvmViewModel;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
ActivityMvvmBinding binding = DataBindingUtil.setContentView(this, R.layout.activity_mvvm);
mvvmViewModel = new MVVMViewModel(getApplication(),binding);
binding.setViewModel(mvvmViewModel);
}
}
<?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.test.myapplication.mvvm.MVVMViewModel"/>
</data>
<LinearLayout
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<EditText
android:id="@+id/edittext"
android:text="@={viewModel.userInput}"
android:hint="请输入要查询的账号"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
<Button
android:layout_gravity="center"
android:id="@+id/button"
android:text="获取账号信息"
android:onClick="@{viewModel.getData}"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
<TextView
android:id="@+id/text"
android:layout_marginTop="50dp"
android:layout_gravity="center"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@{viewModel.result}"
android:hint="账号信息未获取" />
</LinearLayout>
</layout>
public class MVVMViewModel extends BaseObservable {
private String result;
private String userInput;
private MVVMModel model;
private ActivityMvvmBinding binding;
//一般需要传入Application对象,方便在ViewModel中使用application
//比如sharepreferences
public MVVMViewModel(Application application) {
model = new MVVMModel();
}
public MVVMViewModel(Application application, ActivityMvvmBinding binding) {
model = new MVVMModel();
this.binding = binding;
}
public void getData(View view) {
model.getAccountData(userInput, new MCallBack() {
@Override
public void onSuccess(Account account) {
String info = "用户账号:" + account.getName() + "|" + "用户等级:" + account.getLevel();
setResult(info);
}
@Override
public void onFail() {
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);
}
}
public class MVVMModel {
//查询用户数据
public void getAccountData(String accountName, MCallBack mCallBack) {
Random random = new Random();
boolean isSuccess = random.nextBoolean();
if (isSuccess) {
Account account = new Account();
account.setName(accountName);
account.setLevel(100);
mCallBack.onSuccess(account);
} else {
mCallBack.onFail();
}
}
}