1.背景
- MVC:是一种在20世纪80年代出现较早的设计模式。
- MVP:由于MVC本身存在一定的弊端,后来出现了该设计模式
2.特点
2.1.MVC设计模式
- 定义
MVC是由Model(模型),View(视图),Controller(控制器)这三部分组成。
Model:Model层主要是处理与业务相关的代码,与视图View是无关的。
View:这里指的一般是XML代码,或者是自定义View绘制页面。简单来说指的就是页面可视化的部分。
Controller:对Android来说,Controller通常指的就是activity、fragment包括有这些类控制的其他相关类。- 优缺点
优点:代码之间的分工明确、一定程度上提高了开发效率。
缺点:随着项目的复杂度提升,代码会变得很臃肿、View层和Model相互耦合,不易开发和维护。
2.2.MVP设计模式
- 定义
MVP是由Model(模型),View(视图),Presenter(提出者)这三部分组成。
Model:主要提供数据的存储、获取功能。
View:通常指的就是activity、fragment类包括一些展示View的类似于MVC的View差不多。
Presenter:该类可以称之为View和Model类之间沟通的桥梁,主要就是通过实现接口的方式由Model层获取到数据返回给View层,从而View层和Model层之间的解偶合(写程序的要求是高内聚,低耦合)- 优缺点
优点:低耦合、便于维护,成本低等
缺点:需要创建的类过多,对于简单的页面使用MVP降低了可阅读性、需要关注activity或fragment的生命周期,例如在Presenter做网络请求成功回调的时候,要判断activity或fragment是否已被销毁,需要做的处理有点多,阅读性较差。
3.具体使用
3.1.MVC
- 3.1.1.关系图如下:
- 3.1.2.MVC的例子没什么好说的,这里一笔带过,如果你还是不太清楚的话(点击这里)
3.2.MVP
- 3.2.1.关系图如下:
-
3.2.2.接下来上代码(注意注释处的文字描述):
- Activity类的代码
public class LoginActivity extends BaseActivity implements View.OnClickListener, LoginContract.View {
......
private boolean showPassword;
private LoginPresenter mPresenter;
public static void start(Context context) {
Intent intent = new Intent(context, LoginActivity.class);
context.startActivity(intent);
}
@Override
public int setContentLayout() {
return R.layout.activity_login;
}
@Override
public void initToolBar() {
}
@Override
public void initPresenter() {
//注意:部分方法被封装到BaseActivity里面,最终是在onCreate()方法中有调用,
//也就是说Presenter类是在onCreate()里面new的,并且这里也可以不用判空。
if (mPresenter == null) {
mPresenter = new LoginPresenter(this, this);
}
}
@Override
public void initData() {
initListener();
}
@Override
public void onDestroyActivity() {
//这个方法最终是在onDestory()方法中调用,所以在界面销毁时候要将Presenter对象置空,
//这里没有考虑网络请求可能出现延迟页面生命周期的情况。
mPresenter = null;
}
private void initListener() {
......
}
@Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.ib_delete_number:
......
break;
case R.id.ib_delete_password:
......
break;
case R.id.ib_hide_password:
......
break;
case R.id.btn_login:
String number = mEtNumbers.getText().toString().trim();
String password = mEtPasswords.getText().toString().trim();
if (mPresenter != null) {
//下面这个方法是在接口类LoginContract.Presenter中申明的,后面会再做解释
mPresenter.manageNumberAndPassword(number, password);
}
break;
case R.id.tv_register:
RegisterActivity.start(this);
break;
}
}
//这个方法是在接口类LoginContract.View申明的,
//在activity中实现LoginContract.View里面View接口的方法,在Presenter里面调用。
@Override
public void errorRemind(int title, int resId) {
......
}
//这个方法是在接口类LoginContract.View申明的,
//在activity中实现LoginContract.View里面View接口的方法,在Presenter里面调用。
@Override
public void loginSuccess(int successRemind) {
ToastUtil.showToast(this, successRemind);
MainActivity.start(this);
finish();
}
//这个方法是在接口类LoginContract.View申明的,
//在activity中实现LoginContract.View里面View接口的方法,在Presenter里面调用。
@Override
public void loginError(String errorMsg) {
......
}
class MyWatcher implements TextWatcher {
......
}
- Presenter类的代码
public class LoginPresenter implements LoginContract.Presenter {
private static final int mNumberLength = 11;
private static final int mPasswordLength = 6;
private Activity mActivity;
private LoginContract.View mView;
private final ILoginModel mModel;
//将activity和presenter建立链接就是通过这个构造方法
public LoginPresenter(Activity activity, LoginContract.View view) {
this.mActivity = activity;
this.mView = view;
mModel = new LoginModel();//这里是网络请求的封装类,后面再做解释。
}
//这个方法实现的是LoginContract.Presenter这里的,上面activity那里有调用
@Override
public void manageNumberAndPassword(String number, String password) {
if (mView == null) {
return;
}
if (TextUtils.isEmpty(number) || TextUtils.isEmpty(password)) {
//这里mView指的是LoginContract.View的对象,errorRemind()方法是
//LoginContract.View接口类里的,在这里调用,在activity实现,下面同理。
mView.errorRemind(R.string.login_dialog_error, R.string.login_dialog_error_content);
return;
}
if (number.length() < mNumberLength || password.length() < mPasswordLength) {
mView.errorRemind(R.string.login_dialog_remind, R.string.login_dialog_error_remind);
return;
}
mModel.loginInfo(number, password, new ILoginModel.loginListener() {
@Override
public void responseLoginSuccess(LoginBean loginBean) {
mView.loginSuccess(R.string.login_success);
}
@Override
public void responseLoginFail(String errorMsg) {
//请求失败
mView.loginError(errorMsg);
}
});
}
}
- LoginContract接口类代码
//activity和Presenter是通过这个接口类关联起来的,这里要注意Presenter的构造方法。
public interface LoginContract {
//在activity类实现View接口,Presenter类调用View接口
//IBaseVeiw可以添加一写通用方法的封装
interface View extends IBaseView {
void errorRemind(int title, int reeId);
void loginSuccess(int successRemind);
void loginError(String errorMsg);
}
//在Presenter类里实现Presenter接口,在activity类调用Presenter接口
//IBasePresenter可以添加一写通用方法的封装
interface Presenter extends IBasePresenter {
void manageNumberAndPassword(String number, String password);
}
}
- Model类代码
//通常Model类都是用来做网络请求的封装,这里用到的是RxJava2+Retrofit2做的封装
public class LoginModel implements ILoginModel{
@Override
public void loginInfo(String phone, String pwd, final ILoginModel.loginListener listener) {
new AppSubscribe.Builder()
.setFlowable(BaseHttp.getBaseHttp().loginInfo(Constant.HTTP_KEY, phone, pwd))
.subscribe(new AppResponse<LoginBean>() {
@Override
public void onNext(LoginBean loginBean) {
super.onNext(loginBean);
if (listener != null) {
listener.responseLoginSuccess(loginBean);
}
}
@Override
public void onError(Throwable e) {
super.onError(e);
if (listener != null) {
listener.responseLoginFail(e.getMessage());
}
}
}).build();
}
}
- Model接口类代码
public interface ILoginModel {
void loginInfo(String phone, String pwd, ILoginModel.loginListener listener);
interface loginListener {
void responseLoginSuccess(LoginBean loginBean);
void responseLoginFail(String errorMsg);
}
}
注:基本上MVP就是上面说的那个样子,如果没有看懂也没关系,根据下面第4步,下载代码会看可能会更容易理解一些。
4.参考
- 如果你想了解(MVP+RxJava2+Retrofit2)组合的设计模式,请参考我的这个项目:Android_Demo持续完善
5.总结
5.最后
开通了个公众号,扫码关注一下,可以获得超过1个G的免费PDF书籍学习资料,并且可以及时收到我分享的内容哦!
期待你的关注!