简单介绍MVc/MVp
-
MVC全名是(ModelViewController)M-Model-模型、V-View-视图、C-Controller-控制器,MVP作为MVC的演化版本,
-
MVP所对应的意义:M-Model-模型、V-View-视图、P-Presenter-表示器。
-
其中M层处理数据,业务逻辑等。V层处理界面显示结果;C层起到桥梁作用,来控制V层和M层的通信,来进行分离视图显示和业务逻辑层。
- 视图层(View) 一般采用XML文件进行描述,XML理解为AndroidApp的View,使用的时候可以很方便的引入;同时也方便后期界面修改,逻辑中与界面对应的id,如没有变化则代码不需要修改,很好的争强了代码的可维护性。
- 控制层(Controller/Presenter) 在MVP中View并不直接使用Model,它们之间的通信是通过Presenter (MVC中的Controller)来进行的,所有的交互都发生在Presenter内部,而在MVC中View会从直接Model中读取数据而不是通过 Controller。
- 模型层 针对业务模型,建立数据结构和相关类,理解为AndroidApp的Model,Model是与View没有关系,而与业务相关的。对数据库的操作、对网络等的操作都应该在Model里处理,业务等计算操作也必须放在这层,就是应用程序中的二进制的数据。
MVC与MVP对比图如下:
- 什么是MVP:
View:负责绘制UI元素、与用户进行交互(在Android中体现为Activity);为Presenter提供调用Activity中具体UI逻辑操作的方法。
Model:负责储存、检索操作数据。
Presenter:作为View和Model交互的中间纽带,处理与用户交互的负责逻辑,它的作用是为Model层提供调用Presenter层的方法。
1.View只负责简单的视图更新、界面跳转的代码。
个人觉得View从一开始就把自己本身的任务安排好了,再进行给Presenter所需的任务进行分配,如果把View和Presenter进行分开。如果是Presenter太臃肿的话在不同的情况下会现的不仅要多敲一个Fragment,而且在Activity中也是做反复性的工作:new Fragment,addFragment, new Present……
所以View只是做了初始化的动作,根据Presenter所需要的任务分配进行,当指令分配好了,在进行“偷懒”。
2.但是Presenter真的有必要实现接口吗?
在MVP模式中,Presenter是高层次模块,而View是低层次模块。 而使用依赖倒置原则主要是为了高层和低层模块的解耦,方便替换低层次模块的时候不会影响到高层模块,所以在MVP模式中,View需要实现接口,你可以随时将View替换成Activity,Fragment或者其他,并不会印象到Presesnter。
3.Presenter异步任务回来后,通知View更新UI之前,要先判断Activity是否为null,或者Fragment是否已经从activity中移除。
Presenter的生命周期,因为怕 Activity 被回收,然后又调用 View 的方法,出现空指针异常问题,就能有效得避免了在异步任务完成时,Activity/Fragment却已经被销毁而导致的空指针等问题。同时不需要种判断。
4.Context。如果你要在Presenter和Model里面使用Context,那么你应该使用Application的Context,而不是Activity的Context。
理解:Context 使用时注意可以用 ApplicationContext 就用 ApplicationContext, 不能用 ApplicationContext 才用 Context。
实例代码如下:
View接口:
View接口是Activity与Presenter层的中间层,它的作用是根据具体业务的需要,为Presenter提供调用Activity中具体UI逻辑操作的方法
package cn.study.mvp.View;
public interface IMvpview {
/**
* 显示正在加载进度框
*/
void showLoading();
/**
* 隐藏正在加载进度框
*/
void hideLoading();
/**
* 当数据请求成功后,调用此接口显示数据
*
* @param data 数据源
*/
void showData(String data);
/**
* 当数据请求失败后,调用此接口提示
*
* @param msg 失败原因
*/
void showFailureMessage(String msg);
/**
* 当数据请求异常,调用此接口提示
*/
void showErrorMessage();
}
Presenter接口:
presenter接口是presenter和model之间的中间层,它的作用是为Model层提供调用Presenter层的方法。
public interface IMvpPresenter {
void onSuccess(String data);
void onFailure(String msg);
void onError();
void onComplete();
}
Model接口 Model接口作用是提供具体业务逻辑处理的方法
package cn.study.mvp.Model;
public interface IMvpModel {
/**
* 数据请求
*
* @param data
*/
void getNetData(String data);
}
Activity类
public class MainActivity extends AppCompatActivity implements IMvpview, View.OnClickListener {
private MvpPresenter mvpPresenter;
//进度条
ProgressDialog progressDialog;
TextView text;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Button button1 = (Button) findViewById(R.id.btn_1);
button1.setOnClickListener(this);
// 初始化进度条
progressDialog = new ProgressDialog(this);
progressDialog.setCancelable(false);
progressDialog.setMessage("正在加载数据");
mvpPresenter = new MvpPresenter();
mvpPresenter.attachView(this);
}
@Override
public void onClick(View view) {
switch (view.getId()) {
case R.id.btn_1:
mvpPresenter.getData("normal");
break;
}
}
@Override
public void showLoading() {
if (!progressDialog.isShowing()) {
progressDialog.show();
}
}
@Override
public void hideLoading() {
if (progressDialog.isShowing()) {
progressDialog.dismiss();
}
}
@Override
public void showData(String data) {
text.setText(data);
}
@Override
public void showFailureMessage(String msg) {
Toast.makeText(this, msg, Toast.LENGTH_SHORT).show();
text.setText(msg);
}
@Override
public void showErrorMessage() {
Toast.makeText(this, "网络请求数据出现异常", Toast.LENGTH_SHORT).show();
text.setText("网络请求数据出现异常");
}
@Override
protected void onDestroy() {
super.onDestroy();
// 断开View引用
mvpPresenter.detachView();
}
}
Presenter类
public class MvpPresenter implements IMvpPresenter {
private IMvpview iMvpview;
private MvpModel mvpModel;
public void getData(String params) {
iMvpview.showLoading();
mvpModel.getNetData(params);
}
/**
* 绑定view,一般在初始化中调用该方法
*/
public void attachView(IMvpview iMvpview) {
this.iMvpview = iMvpview;
mvpModel = new MvpModel(this);
}
/**
* 断开view,一般在onDestroy中调用
*/
public void detachView() {
this.iMvpview = null;
}
/**
* 是否与View建立连接
* 每次调用业务请求的时候都要出先调用方法检查是否与View建立连接
*/
public boolean isViewAttached() {
return iMvpview != null;
}
@Override
public void onSuccess(String data) {
if (isViewAttached()) {
iMvpview.showData(data);
}
}
@Override
public void onFailure(String msg) {
if (isViewAttached())
iMvpview.showFailureMessage(msg);
}
@Override
public void onError() {
if (isViewAttached())
iMvpview.showErrorMessage();
}
@Override
public void onComplete() {
if (isViewAttached())
iMvpview.hideLoading();
}
}
Model类
public class MvpModel implements IMvpModel {
private IMvpPresenter iMvpPresenter;
public MvpModel(IMvpPresenter iMvpPresenter) {
this.iMvpPresenter = iMvpPresenter;
}
/**
* 获取网络接口数据
*
* @param param 请求参数
*/
@Override
public void getNetData(final String param) {
// 利用postDelayed方法模拟网络请求数据的耗时操作
new Handler().postDelayed(new Runnable() {
@Override
public void run() {
switch (param) {
case "normal":
iMvpPresenter.onSuccess("根据参数" + param + "的请求网络数据成功");
break;
case "failure":
iMvpPresenter.onFailure("请求失败:参数有误");
break;
case "error":
iMvpPresenter.onError();
break;
}
iMvpPresenter.onComplete();
}
}, 2000);
}
}
总结
通过对todo-mvp分析,再次了解学习了MVP。从google提供的例子中可以看出,MVP的实现较为简单,model、view和presenter各个职责明确,便于扩展维护。contract契约类的出现,使得model和presenter结构更加清晰明了。Activity和Fragment的配合,使得Activity职能更为简化,同时View的实现更加灵活。