1.什么是MVP
再说之前先贴两个图
mvc模式
想必大家之前已经清楚了解了MVC模式吧,其实我们之前写的代码风格一致都是mvc模式,UI展示,控制逻辑,还有数据的操作,都写在一起,比如说都写在Activity或者是Fragment。这样写的话,是方便,操作简单。
但是,这样会造成我们的每个界面的代码特别多,耦合性也特别高,代码不好维护,于是出现了mvp模式
mvp模式
mvp最大的好处就是解耦,将架构分层处理,将原先的MVC层,逻辑处理与数据操作分离出来,各层的职责明确。
- View层只做视图展示;
- P层,相当于调度执行官,将View层数据操作拿出来,交给M层处理,并将M层处理完的结果返回给V层,其实他也可以处理部分view 层的部分逻辑,
- M层,即数据实体层,这块的主要作用就是,请求网络请求,数据库。。。等数据操作,将操作好的数据传递到P层;
他们之间通信就是通过接口,这也是MVP模式的最大特点。废话不多说直接以创创网登陆模块为例,撸代码。
- 采用一个契约类管理三个层的接口—–LoginContract
public interface LoginContract {
interface LoginPrenseter {
void popupLogin(String username, String password);
}
interface LoginView {
void showBean(LoginBean loginBean);
}
interface LoginModel {
void login(String username, String password, MyCallBack<LoginBean> myCallBack);
}
}
2.定义一个回调接口 MyCallBack
public interface MyCallBack<T> {
void OnSuccess(T t);
}
3.首先从指挥官P层开始撸代码吧LoginPrenseterImpl ,前面说过他的作用就是——-数据传递和逻辑处理
public class LoginPrenseterImpl implements LoginContract.LoginPrenseter, MyCallBack<LoginBean> {
private LoginContract.LoginView mLoginView;
private LoginContract.LoginModel mLoginModel;
public LoginPrenseterImpl(LoginContract.LoginView loginView) {
mLoginView = loginView;
mLoginModel = new LoginModelImpl();
}
/**
* 将数据操作传递给model层
*
* @param username
* @param password
*/
@Override
public void popupLogin(String username, String password) {
mLoginModel.login(username, password, this);
}
/**
* 将model层操作好的数据返回到View层
* @param loginBean
*/
@Override
public void OnSuccess(LoginBean loginBean) {
mLoginView.showBean(loginBean);
}
}
- 接下来在搞搞model层的操作,他就是请求网络,或者是数据库,或者是其他。
public class LoginModelImpl implements LoginContract.LoginModel {
@Override
public void login(final String username, final String password, final MyCallBack<LoginBean> myCallBack) {
String password_encryptByPublic = RSAUtil.newInstance().encryptByPublic(password);
OkGo.get(HttpUrlList.LoginModule.LOGIN)
.params("account", username)
.params("password", password_encryptByPublic)
.execute(new AbsCallback<LoginBean>() {
@Override
public void onSuccess(LoginBean loginBean, Call call, Response response) {
myCallBack.OnSuccess(loginBean);
}
@Override
public LoginBean convertSuccess(Response response) throws Exception {
return new Gson().fromJson(response.body().string(), LoginBean.class);
}
});
}
}
5.最后是视图层,他只是根据返回来的数据,进行一下数据展示而已
public class LoginActivity extends BaseActivity implements LoginContract.LoginView, View.OnClickListener {
private Button titleBack;//返回按钮
private TextView layoutTitleText;//标题
private ImageView layoutTitleRightIv;//右侧关闭按钮
private EditText loginInputPhoneEt;//输入电话
private EditText loginInputPaswEt;//输入密码
private TextView loginLoginTv;//登录按钮
private TextView loginForgetPwdTv;//忘记密码
private TextView loginRegTv;//
private ImageView loginWxIv;//三方登录微信
private ImageView loginQqIv;//三方登录qq
private ImageView loginWeiboIv;//三方登录微博
private LoginPrenseterImpl loginPrenseter;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
@Override
protected int getLayoutId() {
return R.layout.activity_login;
}
@Override
protected void initView() {
titleBack = (Button) findViewById(R.id.title_back);
layoutTitleText = (TextView) findViewById(R.id.layout_title_text);
layoutTitleRightIv = (ImageView) findViewById(R.id.layout_title_right_iv);
loginInputPhoneEt = (EditText) findViewById(R.id.login_input_phone_et);
loginInputPaswEt = (EditText) findViewById(R.id.login_input_pasw_et);
loginLoginTv = (TextView) findViewById(R.id.login_login_tv);
loginForgetPwdTv = (TextView) findViewById(R.id.login_forget_pwd_tv);
loginRegTv = (TextView) findViewById(R.id.login_reg_tv);
loginWxIv = (ImageView) findViewById(R.id.login_wx_iv);
loginQqIv = (ImageView) findViewById(R.id.login_qq_iv);
loginWeiboIv = (ImageView) findViewById(R.id.login_weibo_iv);
loginLoginTv.setOnClickListener(this);
}
/**
* 指挥官P层的初始化,后期这块可以用Dagger2进行更深的解耦,取消new,减少类与类之间的依赖
*/
@Override
protected void initData() {
loginPrenseter = new LoginPrenseterImpl(this);
}
/**
* 展示P层的数据
*
* @param loginBean
*/
@Override
public void showBean(LoginBean loginBean) {
//TODO:do your want
}
@Override
public void onClick(View view) {
switch (view.getId()) {
case R.id.login_login_tv:
String username = loginInputPhoneEt.getText().toString();
String password = loginInputPaswEt.getText().toString();
/**
* 提交数据,到P层
*/
loginPrenseter.popupLogin(username, password);
break;
}
}
}
到此,一个标准的MVP的demo就写完了,他没有什么固定模式的代码,按照具体业务,具体对待,主要记住三点即可:1. 解耦; 2. 接口 3. 根据业务选技术
鉴于我的团队从MVC开发模式转变到mvp模式,对于此模式不太熟悉,不理解,特稍微做一下改变,取消M层,将所有的操作放在指挥官层(做大哥的真的挺不容易的啊)
好处:一定程度上也能达到解耦,代码简单点;
坏处:P层的交互压力大,由于网络请求框架,更换数据库等,这些随时都能跟换的框架,会造成代码跟改不易,代码调试不易,也违背了MVP模式的初衷。
为了减少这种坏处,特将网络请求,数据库操作,解耦到P层,,业务逻辑还是丢到View层,后期团队水平提高,下个版本在进行优化。
好代码,都是调试出来的。
骚年开始撸代码吧。。。。。。
老套路 来一个契约类管理三个层的接口—–LoginContract 基本没啥变化,就是少了一个model层的接口,外加一个MyCallBack接口
public interface LoginContract {
interface LoginPrenseter {
void popupLogin(String username, String password);
}
interface LoginView {
void showBean(LoginBean loginBean);
}
}
指挥官P层驾到啦。。。。。
public class LoginPrenseterImpl implements LoginContract.LoginPrenseter {
private LoginContract.LoginView mLoginView;
public LoginPrenseterImpl(LoginContract.LoginView loginView) {
mLoginView = loginView;
}
@Override
public void popupLogin(String username, String password) {
String password_encryptByPublic = RSAUtil.newInstance().encryptByPublic(password);
OkGo.get(HttpUrlList.LoginModule.LOGIN)
.params("account", username)
.params("password", password_encryptByPublic)
.execute(new AbsCallback<LoginBean>() {
@Override
public void onSuccess(LoginBean loginBean, Call call, Response response) {
mLoginView.showBean(loginBean);
}
@Override
public LoginBean convertSuccess(Response response) throws Exception {
return new Gson().fromJson(response.body().string(), LoginBean.class);
}
});
}
}
就这么简单,只是将网络这块抽出啦。。。。
最后就是View层啦,他的代码没有变化,还是原来的味道,代码就不贴出出来啦,大家自行脑补
最后,现如今Android主流的解耦技术:MVP开发模式 +Dagger2(动态注入,用俗话说就是减少new的出现)
对大家说一句话,模式是死的,代码也是死的,可是人的思维是活的;新技术固然很重要,但是根据业务选择合适的框架和技术才是王道
**作者:田程凯**
**时间:2017-02-10**