MVP架构在Android开发中的运用

题记

本系列课程简单的介绍了MVC在软件开发中的运用,以及实际运用时该模式存在的一些问题。引出更适合当下情况的MVP与具体的实现过程。在基础MVP框架之上,介绍了Dagger2,Retrofit2,RxJava在MVP模式下的引入理由以及使用。

为什么进行重构?

  1. 便于单元测试的引入(可测试)
  2. 提高代码可读性
  3. 业务逻辑与UI分离

MVC

MVP架构在Android开发中的运用_第1张图片
  • View:视图,泛指我们能够看到的页面。用户可以发起操作在Controller层进行处理,也可以直接对数据层进行处理。

  • Controller:控制器,处理用户交互逻辑,更新View与操作数据。

  • Model:数据层,JavaBean实体类,用于保存实例数据。

优点:层次区分清晰,各部分可直接调用,减少了代码量。

缺点:在android开发的实际运用中,往往是Activity即作为View又作为Controller,需要加载应用的布局和初始化用户界面,接受并处理来自用户的操作请求,以及请求数据并对界面进行刷新。当业务逻辑或者交互上略复杂,会导致整个类的臃肿,进而难易维护。

业务场景

我们用一个非常简单的填写账号密码点击按钮注册的例子。

布局如图所示

MVP架构在Android开发中的运用_第2张图片
图片.png

要求:

  1. 判断账号密码不能为空。
  2. 密码保证6-18位。
  3. 发起网络请求回调判断是否注册成功。

我们来看用MVC方式写的基本代码

private EditText edtAccount;
private EditText edtPassword;
private Button btnRegister;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_login);

    initView();

    initEvent();
}

private void initView() {
    edtAccount = (EditText) findViewById(R.id.edt_account);
    edtPassword = (EditText) findViewById(R.id.edt_password);
    btnRegister = (Button) findViewById(R.id.btn_login);
}

private void initEvent() {
    btnRegister.setOnClickListener(onClickListener);
}

View.OnClickListener onClickListener = new View.OnClickListener() {
    @Override
    public void onClick(View v) {
        doRegister();
    }
};

private void doRegister() {
    if (checkInput()) {
        if (doHttp()) {
            showSuccess();
        } else {
            Toast.makeText(this, "注册失败", Toast.LENGTH_SHORT);
        }
    }
}

private boolean doHttp() {
    return true;
}

private boolean checkInput() {
    if (TextUtils.isEmpty(edtAccount.getText().toString())) {
        showErrorMsg("帐号不能为空");
        return false;
    }

    if (TextUtils.isEmpty(edtPassword.getText().toString())) {
        showErrorMsg("密码不能为空");
        return false;
    }
    return checkPassword();
}

private boolean checkPassword() {
    String password = edtPassword.getText().toString();
    if (password.length() >= 6 && password.length() <= 18)
        return true;

    showErrorMsg("请确认密码为6-18位");

    return false;

}

private void showErrorMsg(String msg) {
    Toast.makeText(this, msg, Toast.LENGTH_SHORT);
}

private void showSuccess() {
    Toast.makeText(this, "注册成功", Toast.LENGTH_SHORT);
}

在不包括网络请求的情况下,上诉代码不包括头文件已经达到了80+行,boom!!!。

MVP

MVP架构在Android开发中的运用_第3张图片

图片来自wiki

  • View:Activity,fragment,View等在Android环境下特有的包下的内容。

  • presenter:业务逻辑处理层,驱动View层更新。区别于View层,包含JAVA层的内容,用于单元测试。

  • Model:数据层,包括网络请求,数据库操作等,将数据回调到P层。

定义一个契约类来对MVP之间的交互接口进行管理,接下来就围绕contract进行展开。

MVP架构在Android开发中的运用_第4张图片
图片.png

先分析下各模块所要处理的事:

View:

  1. 视图绑定
  2. 监听绑定
  3. 错误吐司
  4. 成功吐司

Presenter:

  1. 验证账号密码是否为空
  2. 验证密码长度是否符合
  3. 进行网络请求,根据回调进行吐司

参与交互的方法只有View的Toast方法与Presenter提供的doRegister,于是contract就变成了这个样子

public interface RegisterContract {
    interface View {

        void showSuccessToast();

        void showErrorMsg(String msg);

    }

    interface Presenter {

        void doRegister(String account, String password);

    }

}

准备工作完毕,回到Activity中。

public class MVPMainActivity extends AppCompatActivity implements RegisterContract.View {

    private EditText edtAccount;
    private EditText edtPassword;
    private Button btnRegister;

    private RegisterPresenter mPresenter;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_login);

        //绑定视图
        initView();

        //绑定点击监听事件
        initEvent();

        //初始化presenter
        initPresenter();
    }

    private void initView() {
        edtAccount = (EditText) findViewById(R.id.edt_account);
        edtPassword = (EditText) findViewById(R.id.edt_password);
        btnRegister = (Button) findViewById(R.id.btn_login);
    }

    private void initEvent() {
        btnRegister.setOnClickListener(onClickListener);
    }

    private void initPresenter() {
        mPresenter = new RegisterPresenter(this);
    }


    View.OnClickListener onClickListener = new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            mPresenter.doRegister(edtAccount.getText().toString()
                    , edtPassword.getText().toString());
        }
    };

    @Override
    public void showSuccessToast() {
        Toast.makeText(this, "注册成功", Toast.LENGTH_SHORT);
    }

    @Override
    public void showErrorMsg(String msg) {
        Toast.makeText(this, msg, Toast.LENGTH_SHORT);
    }

}

Presenter实现:

public class RegisterPresenter implements RegisterContract.Presenter {
    RegisterContract.View mView;

    public RegisterPresenter(RegisterContract.View view) {
        mView = view;
    }

    @Override
    public void doRegister(String account, String password) {
        if (checkInput(account, password)) {
            if (doHttp(account, password)) {
                mView.showSuccessToast();
            } else {
                mView.showErrorMsg("注册失败");
            }
        }
    }

    private boolean doHttp(String account, String password) {
        return true;
    }

    private boolean checkInput(String account, String password) {
        if (TextUtils.isEmpty(account)) {
            mView.showErrorMsg("帐号不能为空");
            return false;
        }

        if (TextUtils.isEmpty(password)) {
            mView.showErrorMsg("密码不能为空");
            return false;
        }
        return checkPassword(password);
    }

    private boolean checkPassword(String password) {
        if (password.length() >= 6 && password.length() <= 18)
            return true;

        mView.showErrorMsg("请确认密码为6-18位");

        return false;

    }
}

至此,我们已经使用MVP模式实现了除网络部分的所有代码。

总结

MVP架构在Android开发中的运用_第5张图片

MVP的优势

  1. presenter中所有的代码都是纯JAVA,即不包含Android下的内容,便于单元测试工作的开展;
  2. 代码可读性得到提高;
  3. 两者最主要的区别在于MVP不能进行View和Model的直接交互,从而抽离业务逻辑,使Activity或者Fragment变的不是那么的臃肿。

MVP的缺点

类爆炸。解耦与清晰的代价就是产生过多的类,所以在实现较为简单的页面时,仍可采用MVC的模式进行实现。

demo

参考

Android MVP模式 简单易懂的介绍方式

你可能感兴趣的:(MVP架构在Android开发中的运用)