详谈Android之MVP开发模式

作者: AlicFeng | 来源:发表于2016-04-14 15:36 被阅读447次

    ****前言****
    以前在写Web项目的时候,也许没有过多的考虑项目的开发模式,然而习惯了采用MVC的模式去开发项目,然而最近开发Android项目的时候,总是感觉View和Model联系很紧密,从逻辑上基本不能分离出来,然后就了解到了MVP模式,这种模式View层与Model层完全分离的,从而减轻了Activity的负担。


    • MVP模式的简介
      MVP开发模式是从经典的MVC模式演变过来的,其基本思路都是相通的。简单来说:MVP模式是基于MVC模式的。
      ****M是Model层,提供业务数据****
      ****V是View视图,显示数据****
      ****P是Presenter控制者,进行逻辑处理****

    • MVP模式与MVC模式的区别
    Paste_Image.png

    从图中可以清晰地看出:它们有一个比较明显的区别就是,MVC中是允许Model和View进行交互的;而MVP中很明显,Model与View之间的交互由Presenter完成,并且Presenter与View之间的交互是通过接口的,换句话说:在MVP中View并不直接使用Model,它们之间的通信是通过Presenter来进行的,所有的交互都发生在Presenter内部。


    • MVP模式的优缺点
      优点:降低耦合,代码灵,层级职责更明显,易于单元测试
      缺点:造成类数量爆炸,代码复杂度和学习成本高,在某些场景下presenter的复用会产生接口冗余
      入门的体验:给一个demo你看的话,你会发现MVP模式开发的思路很清晰,但是你会发觉项目会产生很多的类,代码的复杂度会高些。网上常说:虽然mvp基于mvc,但是由于类太多未必可以写的出来。

    • MVP的小实战DEMO
      不想写太多理论性的文笔,接下来讲解demo的编程思路【代码展示-用户登陆】
      ****demo的项目结构****
    Paste_Image.png

    ****Bean**** UserBean毋庸置疑这个必须有的,和mvc一样

    package com.samego.alic.demomvp.bean;
    
    /**
     * UserBean
     * Created by alic on 16-4-13.
     */
    public class User {
        private String username;//用户名
        private String password;//密码
    
        //construct
        public User() {
        }
    
        public User(String username, String password) {
            this.username = username;
            this.password = password;
        }
    
        //set and get start
        public String getUsername() {
            return username;
        }
    
        public void setUsername(String username) {
            this.username = username;
        }
    
        public String getPassword() {
            return password;
        }
    
        public void setPassword(String password) {
            this.password = password;
        }
        //set and get end
    }
    
    

    ****Model**** 从业务上思考,User至少有login()该方法

    package com.samego.alic.demomvp.model;
    
    import com.samego.alic.demomvp.presenter.OnLoginListener;
    
    /**
     *UserModel接口
     * Created by alic on 16-4-13.
     */
    public interface UserModel {
        /**
         * 用户登陆
         * @param username 用户名
         * @param password 密码
         * @param onLoginListener 登陆结果监听是否登陆成功
         */
        void login(String username,String password,OnLoginListener onLoginListener);
    }
    
    package com.samego.alic.demomvp.model;
    
    /**
     *UserModelImpl类实现UserModel接口
     * Created by alic on 16-4-13.
     */
    public class UserModelImpl implements UserModel {
    
        @Override
        public void login(final String username, final String password, final OnLoginListener loginListener) {
            new Thread(){
                @Override
                public void run() {
                    try {
                        //模拟网络数据交互等待时间
                        Thread.sleep(2000);
                        //模拟登陆成功
                        if("alic".equals(username)&&"123456".equals(password)){
                            User user = new User(username,password);
                            loginListener.loginSuccess(user);
                            //模拟登陆失败
                        }else {
                            loginListener.loginFailed();
                        }
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }.start();
        }
    }
    
    package com.samego.alic.demomvp.model;
    
    /**
     *登陆监听接口
     * Created by alic on 16-4-13.
     */
    public interface OnLoginListener {
        /**
         * 用户登陆成功
         * @param user UserBean
         */
        void loginSuccess(User user);
    
        /**
         * 用户登陆失败
         */
        void loginFailed();
    }
    

    ****View**** 难点就是在View这里,View该有哪些方法,因为Presenter与View交互是通过接口。
    简单分析该接口应该有哪些方法,****其实这些方法就是辅助Presenter的逻辑而存在的****

    //获取用户名 密码
    String getUsername();
    String getPassword();
    
    //清空用户名 密码
    void clearUsername();
    void clearPassword();
    
    //显示 隐藏加载
    void showLoading();
    void hideLoading();
    
    //跳转主界面
    void toMainActivity(User user);~~~
    

    //显示错误
    void showFailed();

    Summary
    

    package com.samego.alic.demomvp.view;

    import com.samego.alic.demomvp.bean.User;

    /**
    *用户登录辅助视图view 虽然由activity显示,目的就是辅助Presenter

    • Created by alic on 16-4-13.
      */
      public interface UserLoginView {
      //获取用户名 密码
      String getUsername();
      String getPassword();

      //清空用户名 密码
      void clearUsername();
      void clearPassword();

      //显示 隐藏加载
      void showLoading();
      void hideLoading();

      //跳转主界面
      void toMainActivity(User user);

      //显示错误
      void showFailed();
      }

    package com.samego.alic.demomvp.view;

    /**
    *用户登陆界面主视图view
    *Created by alic on 16-4-13.
    */
    public class LoginActivity extends AppCompatActivity implements UserLoginView, View.OnClickListener {
    private EditText username,password;
    private Button login,reset;
    private ProgressBar loginLoading;
    private UserLoginPresenter loginPresenter = new UserLoginPresenter(this);
    @Override
    protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_login);
    Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
    setSupportActionBar(toolbar);
    StatusBarCompat.setStatusBarColor(this,StatusBarCompat.COLOR_ToolBar_HIGHTBLUE);
    //初始化
    initViews();
    }

    /**
     * 初始化视图组件
     */
    public void initViews(){
        username = (EditText) findViewById(R.id.login_username);
        password = (EditText) findViewById(R.id.login_password);
        login = (Button) findViewById(R.id.login_button);
        reset = (Button) findViewById(R.id.reset_button);
        loginLoading = (ProgressBar) findViewById(R.id.login_loading);
        loginLoading.setVisibility(View.INVISIBLE);
    
        login.setOnClickListener(this);
        reset.setOnClickListener(this);
    }
    
    @Override
    public String getUsername() {
        return username.getText().toString();
    }
    
    @Override
    public String getPassword() {
        return password.getText().toString();
    }
    
    @Override
    public void clearUsername() {
        username.setText("");
    }
    
    @Override
    public void clearPassword() {
        password.setText("");
    }
    
    @Override
    public void showLoading() {
        loginLoading.setVisibility(View.VISIBLE);
    }
    
    @Override
    public void hideLoading() {
        loginLoading.setVisibility(View.INVISIBLE);
    }
    
    @Override
    public void toMainActivity(User user) {
    

    // Intent intent = new Intent(LoginActivity.this,MainActivity.class);
    // startActivity(intent);
    Toast.makeText(this,"登陆成功",Toast.LENGTH_SHORT).show();

    }
    
    @Override
    public void showFailed() {
        Toast.makeText(this,"用户名或密码错误",Toast.LENGTH_SHORT).show();
    }
    
    @Override
    public void onClick(View v) {
        switch (v.getId()){
            case R.id.login_button:
                loginPresenter.login();
                break;
            case R.id.reset_button:
                loginPresenter.clear();
                break;
            default:
                break;
        }
    }
    

    }

    ****Presenter****  Presenter是用作Model和View之间交互的桥梁,该方法也应该有哪些方法呢,****这些方法其实就是我们在界面上所看到的逻辑处理****,比如login()以及reset()
    

    package com.samego.alic.demomvp.presenter;

    /**
    *UserLoginPresenter

    • Presenter负责完成UserLoginView层与UserModel层的交互

    • Created by alic on 16-4-13.
      */
      public class UserLoginPresenter {
      private UserModel userModel;
      private UserLoginView userLoginView;
      private Handler handler = new Handler();

      //construct
      public UserLoginPresenter(UserLoginView userLoginView) {
      this.userLoginView = userLoginView;
      userModel = new UserModelImpl();
      }

      /**

      • 登陆function
        */
        public void login(){
        userLoginView.showLoading();
        userModel.login(userLoginView.getUsername(), userLoginView.getPassword(), new OnLoginListener() {
        @Override
        public void loginSuccess(final User user) {
        handler.post(new Runnable() {
        @Override
        public void run() {
        userLoginView.toMainActivity(user);
        userLoginView.hideLoading();
        }
        });
        }

         @Override
         public void loginFailed() {
             handler.post(new Runnable() {
                 @Override
                 public void run() {
                     userLoginView.showFailed();
                     userLoginView.hideLoading();
                 }
             });
         }
        

        });
        }

      /**

      • 清空function
        */
        public void clear(){
        userLoginView.clearUsername();
        userLoginView.clearPassword();
        }
        }
    
    以上就是一个非常精简又经典的Demo,对于有些不了解的或者不对的地方欢迎交谈,THX!

    相关文章

      网友评论

      • 竹羔:话说你给的mvc的图应该是错的。mvc是c单向访问m。。 :relieved:
        AlicFeng: @竹羔 哈哈,刚发现,稍后修改(^3^)
      • null_null_:相当详细,THK先~晚上我把这个demo敲一敲
      • AlicFeng:@宇间草木 谢谢提醒!thank you
      • Coopsrc:图反了

      本文标题:详谈Android之MVP开发模式

      本文链接:https://www.haomeiwen.com/subject/qjsglttx.html