1.MVP模式的简介:
相对于mvc,mvp模式中p就是presenter的缩写,意思相当于主持人,它协调view和model的连接,view和model相当于是两个不认识的人,他们中间的中介就是presenter,p持有m和v两个的联系方式。view要处理页面就要要数据,就去找p,让p去拿数据。而p呢就会直接找m去要数据,m把数据给p,然后p拿着数据进行加工,然后给v有用的数据,来用于v的展示。这个过程很像我们通过中介找房子。中介有我们和出租房的联系方式,可以通过查询系统,获取到出租房的房源信息,然后给我们最后有用的信息,比如房屋价格,环境等。但是我们是和房东没有办法直接联系的。这就是mvp。而mvc的话v是可以持有model数据的,这就导致v可能会对model做数据修改。导致会掺杂一些业务逻辑。使得业务逻辑在m和c以及v中混杂到一起。这个典型的例子就是activity。既要控制显示,还要管理数据。非常混乱。而为了更好的分层,还有后续如果我换v和m都没有很大影响的话,我们就延伸出了mvp。就如那个中介,它可以换一套查询系统和房东信息,也可以换租户,但是实现的模式还是不变的。
2.MVP模式具体使用方法:
在项目中的使用:
我们通常需要以接口的形式来实现三者的关系,这样方便后续的扩展。
以登陆为例:
Model:
/*** 描述:登录界面请求接口* */ public interface LoginInteractor extends MvpInteractor { /** * 登录 * @param phone * @param pwd * @param loginInteractorListener */ void userLogin(String phone, String pwd, LoginInteractorListener loginInteractorListener); /** * 请求接口监听器 */ interface LoginInteractorListener { /** * 请求成功且业务代码 也成功 */ void succeed(); /** * 请求成功,但是业务代码失败 * @param message */ void failed(String message); /** * 请求失败 * * @param error */ void connectFail(String error); } }
View:
/** * 描述: * 作者:58 on 2016/5/11 10:41 */ public interface LoginView extends MvpView { /** * 登录成功view显示 */ void loginSucceed(); /** * 登录失败view显示 * @param message */ void loginFailed(String message);void showNotice(String message);
void showNotice(String message);
/**
* 返回当前登录界面btn的状态
* @param canClick
*/
void isCanClick(boolean canClick);
void loadingDismiss();
}
Presenter:
/*** 描述:登录界面逻辑控制器 */ public interface LoginPresenter extends MvpPresenter<LoginView> { /** * 登录 * @param phone * @param pwd */ void login(String phone, String pwd, String validcode); /** * 检测是否可以点击登录btn * @param userPhone * @param password */ void checkClickBtn(String userPhone, String password); }
public interface MvpPresenter<T extends MvpView> {
/**
* 将MVP的View附加到Presenter
*/
void attachView(T view);
void attachView(T view,ViewGroup rootView);
void detachView();
}
具体的实现类如下:
/**Model:* 描述:登录界面逻辑控制器实现 */ public class LoginPresenterImpl implements LoginPresenter, LoginInteractor.LoginInteractorListener, GetPictureVerCodeInteractor.GetPictureVerCodeInteractorListener { private LoginView mLoginView; private Context mContext; private LoginInteractor mLoginInteractor; public LoginPresenterImpl(Context context) { mContext = context; mAccount = Account.getAccount(mContext); } @Override public void attachView(LoginView view) { mLoginView = view; mLoginInteractor = new LoginInteractorImpl(mContext); } @Override public void attachView(LoginView view, ViewGroup rootView) { } @Override public void detachView() { mLoginInteractor.cancelAllRequest(); mContext = null; mLoginView = null; } @Override public void login(String phone, String pwd, String validcode) { mLoginInteractor.userLogin(phone, pwd, this); } @Override public void checkClickBtn(String userPhone, String password) { boolean canClick = !userPhone.isEmpty() && userPhone.length() == 11 && !password.isEmpty() && password.length() >= 6; mLoginView.isCanClick(canClick); } @Override public void succeed() { mLoginInteractor.sendPPU(this); } @Override public void failed(String message) { mLoginView.loginFailed(message); } @Override public void connectFail(String error) { mLoginView.showNotice(error); } @Override public void requestFinish() { mLoginView.loadingDismiss(); } }
/*** 描述:登录界面请求接口实现类 */ public class LoginInteractorImpl implements LoginInteractor { public Context mContext; public LoginInteractorImpl(Context context) { mContext = context; } @Override public void cancelRequest(String requestTag) { HttpManager.getHttpManagerBase(mContext).cancelRequest(requestTag); } @Override public void cancelAllRequest() { HttpManager.getHttpManagerBase(mContext).cancelRequest(ConstantConfig.LOGIN_TAG); mContext = null; } @Override public void userLogin(final String phone, final String pwd, final String validcode, final String vcodekey, final LoginInteractorListener loginInteractorListener) { final Map<String, String> map = setParams(phone, pwd, validcode, vcodekey); LogUtil.i("userlogin", map.toString()); String url = "http://test/login; //这里只做示例 HttpManager.getHttpManagerBase(mContext).httpPost(url, map, ConstantConfig.LOGIN_TAG, new RequestResultListener() { @Override public void onSuccess(String info, Object tag) { Log.e("--------------", info); Gson gson = new Gson(); LoginInfo loginInfo = gson.fromJson(info, LoginInfo.class); if (loginInfo != null) { loginInteractorListener.succeed(); } loginInteractorListener.requestFinish(); } @Override public void onFail(String code, String msg, String info, Object tag) { loginInteractorListener.failed(msg); loginInteractorListener.requestFinish(); } @Override public void connectFail(NetworkResponse error, Object tag) { LogUtil.i("wuba", "connectFail"); loginInteractorListener.connectFail("网络异常请重试"); loginInteractorListener.requestFinish(); } }); } }
我们可以让我们的Activity实现View的接口即可。如下
以上的代码中删去了一部分和公司相关的字段和数据,只是给大家做一个示例,不要生搬硬套。v和m的书写完全看个人的业务需求。public class LoginActivity extends BaseActivity implements LoginView {
。。。。。此处隐去1000字 public void loginSucceed() { ToastUtil.show(this, "登录成功"); if (mDialog != null) { dialogIsShow = false; mDialog.dismiss(); } loginIntent(); } @Override public void loginFailed(String message) { if (mDialog != null) { mDialog.dismiss(); dialogIsShow = false; } if (TextUtils.isEmpty(message)) { message = "登陆异常,请稍后重试!"; } ToastUtil.show(this, message); } @Override public void showNotice(String message) { ToastUtil.show(this, message); } @Override public void isCanClick(boolean canClick) { if (canClick) { loginLoginButton.setBackgroundResource(R.drawable.wb_login_btn_xml); loginLoginButton.setClickable(canClick); } else { loginLoginButton.setBackgroundResource(R.drawable.wb_unlogin_btn_xml); loginLoginButton.setClickable(canClick); } } @Override public void loadingDismiss() { qianguiAccountLoading.statusToNormal(); qianguiAccountLoading.setVisibility(View.GONE); }@Override
}
当我们需要替换登陆页面,或者需要替换登陆方式时,这时就会发现我们只需要动View和model即可。p就可以完全保持不动。
如果大家有什么不理解的地方,也可以给我留言。