MVP架构模式

转载   https://github.com/dance609195946/MVPSample

MVP架构模式入门案例,在众多案例中,应该算是比较规范和容易理解的案例了。(请无视我的自恋)

MVP架构模式详解

  • 概念解释
    • MVP是Model(数据) View(界面) Presenter(表现层)的缩写,它是MVC架构的变种,强调Model和View的最大化解耦和单一职责原则;
    • Model:负责数据相关的业务逻辑,包括数据库,网络,本地缓存,内存数据的业务逻辑处理,并提供接口暴露自己处理数据的状态和进度。
    • View:负责UI相关的业务逻辑,包括显示对话框,Toast,展示listview,gridview等所有的UI相关逻辑,并提供接口暴露自己处理UI逻辑的状态和进度。
    • Presenter:Model和View的互相调用的桥梁,本身不应该有任何具体的逻辑代码,只是在对应的状态下调用Model和View的方法实现数据相关逻辑和UI展示相关逻辑,并且与Fragment和Activity直接打交道;
    • 目前MVP的P有分歧,部分人当Presenter独立抽出,与Activity或Fragment交互,还有部分人直接将Activity和Fragment充当Presenter
  • 先看看一个登录界面的数据业务逻辑和UI逻辑全部写在Activity的代码:
    public class LoginActivity extends ActionBarActivity implements OnClickListener{
        EditText etUsername,etPassword;
        Button btn_login;
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
            etUsername = (EditText) findViewById(R.id.et_username);
            etPassword = (EditText) findViewById(R.id.et_password);
            btn_login = (Button) findViewById(R.id.btn_login);

            //设置点击事件
            btn_login.setOnClickListener(this);
        }
        @Override
        public void onClick(View v) {
            switch (v.getId()) {
            case R.id.btn_login:
                String username = etUsername.getText().toString();
                String password = etPassword.getText().toString();

                if(checkInput(username,password)){
                    //提交登录
                    //显示正在登录对话框
                    showLoginDialog(this);
                    //执行登录请求
                    execLogin(username, password);
                }

                break;
            }
        }

        private ProgressDialog progressDialog;
        //显示登录进度对话框
        public void showLoginDialog(Context context){
            if(progressDialog==null){
                progressDialog = new ProgressDialog(context);
                progressDialog.setTitle("正在登录中...");
            }
            progressDialog.show();
        }
        //关闭登录进度对话框
        public void hideLoginDialog(Context context){
            if(progressDialog!=null){
                progressDialog.dismiss();
            }
        }

        //执行登录请求
        public void execLogin(String username,String password){
            //执行登录请求的伪代码
            HttpHelper helper = new HttpHelper();
            helper.execRequest("http://www.baidu.com", new HttpCallback() {
                @Override
                public void onSuccess() {
                    //关闭登录对话框
                    hideLoginDialog(LoginActivity.this);
                    //提示登录成功
                    showLoginSuccess(LoginActivity.this);

                    //保存登录相关数据,如登录的标记,用户的唯一标识
                    saveLoginData();
                }
                @Override
                public void onFail() {
                    //关闭登录对话框
                    hideLoginDialog(LoginActivity.this);
                    //提示登录失败
                    showLoginFail(LoginActivity.this);
                }
            });
        }
        //保存登录数据
        public void saveLoginData(){
            //保存登录相关的数据,代码略过...
        }
        //提示登录成功
        public void showLoginFail(Context context){
            Toast.makeText(context, "登录失败", 0).show();
        }
        //提示登录失败
        public void showLoginSuccess(Context context){
            Toast.makeText(context, "登录成功", 0).show();
        }
        //检查输入的合法性
        private boolean checkInput(String username, String password) {
            boolean result = true;
            //1.检查为空
            if(TextUtils.isEmpty(username) || TextUtils.isEmpty(password)){
                Toast.makeText(this, "用户名或者密码不能为空!", 0).show();
                result = false;
            }
            //2.检查长度
            if(username.length()!=11){
                Toast.makeText(this, "用户名长度不正确!", 0).show();
                result = false;
            }
            if(password.length()<5){
                Toast.makeText(this, "密码长度不能小于5位!", 0).show();
                result = false;
            }
            return result;
        }
    }
  • 现在抽取出LoginModel,LoginView和LoginPresenter类,如下:

    • LoginView类:

      /**
       * 负责登录模块相关的UI等所有UI相关逻辑
       * @author lxj
       *
       */
      public class LoginView {
          public void showLoginSuccess(Context context){
              Toast.makeText(context, "登录成功", 0).show();
          }
          public void showLoginFail(Context context){
              Toast.makeText(context, "登录失败", 0).show();
          }
          public void showInputNoNull(Context context){
              Toast.makeText(context, "用户名和密码不能为空!", 0).show();
          }
          public void showUsernameLengthError(Context context){
              Toast.makeText(context, "用户名长度不正确!", 0).show();
          }
          private ProgressDialog progressDialog;
          //显示登录中对话框
          public void showLoginDialog(Context context){
              if(progressDialog==null){
                  progressDialog = new ProgressDialog(context);
                  progressDialog.setTitle("正在登录中...");
              }
              progressDialog.show();
          }
          //隐藏登录中对话框
          public void hideLoginDialog(Context context){
              if(progressDialog!=null){
                  progressDialog.dismiss();
              }
          }
      }
      
    • LoginModel类如下:

      /**
       * 负责处理登录相关数据的业务逻辑,并根据数据处理的状态和进度
       * 暴露接口,通知外界
       * @author lxj
       * 
       */
      public class LoginModel {
          private LoginModelObserver loginModelObserver;
          public void setLoginModelObserver(LoginModelObserver loginModelObserver) {
              this.loginModelObserver = loginModelObserver;
          }
          // 执行登录请求
          public void execLogin(String username, String password) {
              if(!checkInput(username, password)){
                  return;
              }
              // 执行登录请求的伪代码
              HttpHelper helper = new HttpHelper();
              helper.execRequest("http://www.baidu.com", new HttpCallback() {
                  @Override
                  public void onSuccess() {
                      // 需要UI展示,暴露接口
                      if(loginModelObserver!=null){
                          loginModelObserver.onLoginSuccess();
                      }
                      // 保存登录相关数据,如登录的标记,用户的唯一标识
                      saveLoginData();
                  }
                  @Override
                  public void onFail() {
                      // 需要UI展示,暴露接口
                      if(loginModelObserver!=null){
                          loginModelObserver.onLoginFail();
                      }
                  }
              });
          }
          // 保存登录数据
          public void saveLoginData() {
              // 保存登录相关的数据,代码略过...
          }
          // 检查输入的合法性
          private boolean checkInput(String username, String password) {
              boolean result = true;
              // 1.检查为空
              if (TextUtils.isEmpty(username) || TextUtils.isEmpty(password)) {
                  if (loginModelObserver != null) {
                      loginModelObserver.onInputNoNull();
                  }
                  result = false;
              }
              // 2.检查长度
              if (username.length() != 11) {
                  if (loginModelObserver != null) {
                      loginModelObserver.onUsernameLengthError();
                  }
                  result = false;
              }
              return result;
          }
      
          // 定义数据处理状态的回调
          public interface LoginModelObserver {
              // 输入数据不能为空的回调
              void onInputNoNull();
              // 用户名长度不正确的回调
              void onUsernameLengthError();
              //登录成功的回调
              void onLoginSuccess();
              //登录失败的回调
              void onLoginFail();
          }
      }
      
    • LoginPresenter类如下:

      /**
       * 负责连接LoginView和LoginModel的表现层
       * 具体就是调用LoginModel和LoginView的方法
       * @author lxj
       *
       */
      public class LoginPresenter implements LoginModelObserver{
          private LoginModel loginModel;
          private LoginView loginView;
          private Context context;
          public LoginPresenter(Context context){
              this.context = context;
      
              loginModel = new LoginModel();
              loginView = new LoginView();
      
              loginModel.setLoginModelObserver(this);
          }
          //登录的方法
          public void login(String username, String password) {
              //调用loginModel封装好的方法
              loginModel.execLogin(username, password);
          }
          @Override
          public void onInputNoNull() {
              //调用loginView展示UI的方法
              loginView.showInputNoNull(context);
          }
          @Override
          public void onUsernameLengthError() {
              loginView.showUsernameLengthError(context);
          }
          @Override
          public void onLoginSuccess() {
              loginView.showLoginSuccess(context);
          }
          @Override
          public void onLoginFail() {
              loginView.showLoginFail(context);
          }
      }
      
    • 最后LoginActivity实现如下:

      public class LoginActivity extends ActionBarActivity implements OnClickListener{
          EditText etUsername,etPassword;
          Button btn_login;
          private LoginPresenter loginPresenter;
          @Override
          protected void onCreate(Bundle savedInstanceState) {
              super.onCreate(savedInstanceState);
              setContentView(R.layout.activity_main);
              etUsername = (EditText) findViewById(R.id.et_username);
              etPassword = (EditText) findViewById(R.id.et_password);
              btn_login = (Button) findViewById(R.id.btn_login);
      
              //设置点击事件
              btn_login.setOnClickListener(this);
      
              //与loginPresenter交互
              loginPresenter = new LoginPresenter(this);
          }
          @Override
          public void onClick(View v) {
              switch (v.getId()) {
              case R.id.btn_login:
                  String username = etUsername.getText().toString();
                  String password = etPassword.getText().toString();
                  loginPresenter.login(username,password);
                  break;
              }
          }
      }
      
  • 总结:MVP只是给我们提出了分层解耦的思想,并没有一个固定的实现。Google虽然出了官方的MVP实现示例,但是并没有太多人去跟随,很多公司在对Presenter层都有自己的理解,俊哥给给出的也是自己的理解,此处的案例相对来说比较规范,对MVP三层都有清晰的解耦和实现,在茫茫开源项目中,算是比较好的容易理解的上手项目了。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值