1.什么是MVP

再说之前先贴两个图

Android mvp不合理 android开发mvp模式_ide


mvc模式

想必大家之前已经清楚了解了MVC模式吧,其实我们之前写的代码风格一致都是mvc模式,UI展示,控制逻辑,还有数据的操作,都写在一起,比如说都写在Activity或者是Fragment。这样写的话,是方便,操作简单。

  但是,这样会造成我们的每个界面的代码特别多,耦合性也特别高,代码不好维护,于是出现了mvp模式

Android mvp不合理 android开发mvp模式_Android mvp不合理_02


mvp模式

mvp最大的好处就是解耦,将架构分层处理,将原先的MVC层,逻辑处理与数据操作分离出来,各层的职责明确。

  • View层只做视图展示;
  • P层,相当于调度执行官,将View层数据操作拿出来,交给M层处理,并将M层处理完的结果返回给V层,其实他也可以处理部分view 层的部分逻辑,
  • M层,即数据实体层,这块的主要作用就是,请求网络请求,数据库。。。等数据操作,将操作好的数据传递到P层;

他们之间通信就是通过接口,这也是MVP模式的最大特点。废话不多说直接以创创网登陆模块为例,撸代码。

  1. 采用一个契约类管理三个层的接口—–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);
    }

}
  1. 接下来在搞搞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**