MVPDemo

Project Url: HaoTianYi/MVPDemo
Introduction: MVP 模式(Model-View-Presenter)可以说是 MVC 模式(Model-View-Controller)在 Android 开发上的一种变种、进化模式。
More: Author   ReportBugs   DemoAPK   
Tags:
设计模式-mvp-

整理自mvp

简介

MVP 模式(Model-View-Presenter)可以说是 MVC 模式(Model-View-Controller)在 Android 开发上的一种变种、进化模式。

在 MVC 模式中,Activity 应该是属于 View 这一层。而实质上,它既承担了 View,同时也包含一些 Controller 的东西在里面。这对于开发与维护来说不太友好,耦合度大高了。把 Activity 的 View 和 Controller 抽离出来就变成了 View 和 Presenter,这就是 MVP 模式。

MVC 模式

MVC 模式的结构分为三部分,实体层的 Model,视图层的 View,以及控制层的 Controller。

sp161121_161924

  • 其中 View 层其实就是程序的 UI 界面,用于向用户展示数据以及接收用户的输入
  • 而 Model 层就是 JavaBean 实体类,用于保存实例数据
  • Controller 控制器用于更新 UI 界面和数据实例

MVP 模式

按照 MVC 的分层,Activity 和 Fragment(后面只说 Activity)应该属于 View 层,用于展示 UI 界面,以及接收用户的输入,此外还要承担一些生命周期的工作。Activity 是在 Android 开发中充当非常重要的角色,特别是 TA 的生命周期的功能,所以开发的时候我们经常把一些业务逻辑直接写在 Activity 里面,这非常直观方便,代价就是 Activity 会越来越臃肿,所以看起来有必要在 Activity 中,把 View 和 Controller 抽离开来,而这就是 MVP 模式的工作了。

sp161121_162259

核心思想:

MVP 把 Activity 中的 UI 逻辑抽象成 View 接口,把业务逻辑抽象成 Presenter 接口,Model 类还是原来的 Model

这就是 MVP 模式,现在这样的话,Activity 的工作的简单了,只用来响应生命周期,其他工作都丢到 Presenter 中去完成。

MVP 模式的使用

sp161121_164834

上面一张简单的 MVP 模式的 UML 图,从图中可以看出,使用 MVP,至少需要经历以下步骤:

  1. 创建 IPresenter 接口,把所有业务逻辑的接口都放在这里,并创建它的实现 PresenterCompl(在这里可以方便地查看业务功能,由于接口可以有多种实现所以也方便写单元测试)
  2. 创建 IView 接口,把所有视图逻辑的接口都放在这里,其实现类是当前的 Activity/Fragment
  3. 由 UML 图可以看出,Activity 里包含了一个 IPresenter,而 PresenterCompl 里又包含了一个 IView 并且依赖了 Model。Activity 里只保留对 IPresenter 的调用,其它工作全部留到 PresenterCompl 中实现
  4. Model 并不是必须有的,但是一定会有 View 和 Presenter

MVP 的主要特点就是把 Activity 里的许多逻辑都抽离到 View 和 Presenter 接口中去,并由具体的实现类来完成。这种写法多了许多 IView 和 IPresenter 的接口

具体代码

一个简单的登录界面:

sp161121_173136

/**
 * @author HaoTianYi hao.ty@haotianyi.win
 * @version v1.0
 * @des   作为 view 的实现
 * @time 2016-11-21 17:00
 */
public class MainActivity extends AppCompatActivity implements IView,View.OnClickListener{

    IPresenter mPresenter;

    private EditText editUser;
    private EditText editPass;
    private Button btnLogin;
    private Button   btnClear;
    private ProgressBar progressBar;

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

        //find view
        editUser = (EditText) this.findViewById(R.id.et_login_username);
        editPass = (EditText) this.findViewById(R.id.et_login_password);
        btnLogin = (Button) this.findViewById(R.id.btn_login_login);
        btnClear = (Button) this.findViewById(R.id.btn_login_clear);
        progressBar = (ProgressBar) this.findViewById(R.id.progress_login);

        //set listener
        btnLogin.setOnClickListener(this);
        btnClear.setOnClickListener(this);

        //init
        mPresenter = new PresenterCompl(this);
        mPresenter.setProgressBarVisiblity(false);
    }

    @Override
    public void onClesrText() {
        editUser.setText("");
        editPass.setText("");
    }

    @Override
    public void onSuccessAndRefuslView(boolean result) {
        Toast.makeText(MainActivity.this,result?"成功":"失败",Toast.LENGTH_SHORT).show();
    }

    @Override
    public void onShowDIalog(boolean result) {
        progressBar.setVisibility(result?View.VISIBLE:View.GONE);
    }

    @Override
    public void onClick(View v) {
        switch (v.getId()){
            case R.id.btn_login_clear:
                mPresenter.setClearText();
                break;
            case R.id.btn_login_login:
                mPresenter.setProgressBarVisiblity(true);
                btnLogin.setEnabled(false);
                btnClear.setEnabled(false);
                mPresenter.doLogin(editUser.getText().toString(), editPass.getText().toString());
                break;
        }
    }

IPresenter 的写法:

/**
 * @author HaoTianYi hao.ty@haotianyi.win
 * @version v1.0
 * @des   三个方法,控制视图的不同显示
 * @time 2016-11-21 17:08
 */

public interface IPresenter {
    /**
     * 清空输入框的文字
     */
    void setClearText();

    /**
     * 登录操作
     * @param name
     * @param passwd
     */
    void doLogin(String name, String passwd);

    /**
     * 设置 progressBar 是否显示
     * @param result
     */
    void setProgressBarVisiblity(boolean result);
}

IModel 的写法:

/**
 * @author HaoTianYi hao.ty@haotianyi.win
 * @version v1.0
 * @des   获得用户的用户名和密码并且判断是否符合规则
 * @time 2016-11-21 17:03
 */

public interface IModel {
    String getName();
    String getPssword();
    boolean isSuccess(String name,String password);
}

PresenterCompl 的写法:

public class PresenterCompl implements IPresenter {

    IView mIView;
    IModel mIModel;
    Handler mHandler;

    public PresenterCompl(IView iView) {
        mIView = iView;

        mHandler = new Handler(Looper.getMainLooper());
    }


    @Override
    public void setClearText() {
        mIView.onClesrText();
    }

    @Override
    public void doLogin(final String name, final String passwd) {
        mIModel = new ModelCompl(name, passwd);
        final boolean isSuccess = mIModel.isSuccess(name, passwd);
        mHandler.postDelayed(new Runnable() {
            @Override
            public void run() {
                mIView.onSuccessAndRefuslView(isSuccess);
                mIView.onShowDIalog(!isSuccess);
            }
        }, 3000);
    }


    @Override
    public void setProgressBarVisiblity(boolean result) {
        mIView.onShowDIalog(result);
    }

具体代码:GitHub

Apps
About Me
GitHub: Trinea
Facebook: Dev Tools