关于mvp

来源:互联网 发布:运营商的云计算项目 编辑:程序博客网 时间:2024/06/06 22:00

说到mvp 不得不说的就是mvc 了 来先看一个经典的图

这里写图片描述

C和P的区别

1、先看C
C 就是 Controller,控制器。负责从 View 读取数据,控制用户输入,并向 Model 发送数据。简单来说,就是起到一个沟通的作用,能很大程度上的解决 Model 和 View 的耦合问题。

换句话说就是,它是一个 Model 与 View 之间的桥梁,让 Model 和 View 之间不再紧紧关联。

比如 View 接收到了用户输入数据,先交给 Controller ,Controller 再转交给 Model ,反之亦然。

但是如果controller 有问题 view 跟model 也能直接沟通

2、观察一下P

p即 Presenter 主持人。。。好 我们叫主持吧。。 作用跟跟 C 类似,仍然是负责 View 和 Model 之间的沟通。但是它彻底让 View 和 Model 不能直接沟通。如果想要沟通,就必须通过这个主持者来主持它们两个应该干啥。

比如 View 接收到了用户输入数据,不能直接给 Model ,要交给 Presenter ,Presenter 再转交给 Model ,反之亦然。

如果view接收到了用户操作必须要先交给Presenter再通过Presenter去转交给model 反过来也是 当model 改变了 也必须通过Presenter来反过来通知view去更新 不能像mvc一样model 改变view直接就能刷新了

3、简单的区别
C 和 P 都是为了解放 Model 和 View 之间的联系,只不过 C 是很大程度上解决,但 P 是彻底让它们两断了联系。

也就是c让model 、View 松散耦合,p让Model、View 解耦

来看下详细的区别

1、mvc
从下图中我们可以看到

这里写图片描述
*用户 Event(事件)会导致 Controller 改变 Model 或 View 或同时改变两者。

*只要 Controller 改变了 Model 的数据或属性,所有依赖的 View 都会自动更新。

*类似的,只要 Controller 改变了 View ,View 会从潜在的 Model 中获取数据进行更新。

2、mvp
这里写图片描述
Presenter 中同时持有 View 以及 Model 的 Interface 引用,而 View 持有 Presenter 的实例。

当某个 View 需要展示某些数据时,首先会调用 Presenter 的某个接口,然后 Presenter 会调用 Model 请求数据。

当 Model 数据加载成功后会调用 Presenter 的回调方法通知 Presenter 数据加载完毕,最后 Presenter 再调用 View 层接口展示加载后数据。

3、主要区别

在 MVC 中:

  • View 可以与 Model 直接交互;

  • Controller 可以被多个 View 共享;

  • Controller 可以决定显示哪个 View。

在 MVP 中:

  • View 不直接与 Model 交互;

  • Presenter 与 View 通过接口来交互,更有利于添加单元测试;

  • 通常 View 与 Presenter 是一对一的,但复杂的 View 可能绑定多个 Presenter 来处理;

  • Presenter 也可以直接进行 View 上的渲染。

好先看下经典的目录结构吧

这里写图片描述

好像是看不出什么来 这就是一个简单的登陆demo 万年不变
我们可以来分析一下

通过上面的介绍我们可以知道,Presenter 是用来Model 和View 之间交互的 所以必须要持有他们各自的对象

model 还要有一个业务类 这在mvc中也是一样的 索性我们就抽一个接口出来

Presenter 与view 又是通过接口来交互的所以我们就需要给view 定义一个接口

所以我们就要看到底需要什么东西

  • Model:负责检索操作数据,也就是常见的业务类对bean的操作

  • ModelInterface: 处理bean的业务逻辑接口 由bean来实现

  • view:暂时就看出activity 用来记录响应用户操作的

  • viewInterface : view 要实现用户操作的结果接口(比如登陆 界面上肯定有登陆注册按键 就要有 登陆成功失败的接口以及注册成功失败的接口)Presenter 通过 它 与view交互

  • Presenter 是个类 是用来连接view 与model的桥梁 持有二者的接口对象

  • 好吧 看起来非常多 但是逻辑确实是清晰了一点 谁是干什么的 谁控制谁响应 这种是清晰了一点。。我体会还不深 勿喷

ok 现在我们可以抽取代码了

1、bean

   /** * Created by MnyZhao on 2017/11/3. */public class UserBean {    /*名字*/    private String name;    /*密码*/    private String passWord;    public String getName() {        return name;    }    public void setName(String name) {        this.name = name;    }    public String getPassWord() {        return passWord;    }    public void setPassWord(String passWord) {        this.passWord = passWord;    }} 

2、业务操作接口 业务操作类 针对bean

UserModelInterface

/** * Created by MnyZhao on 2017/11/3. *  @description  业务操作接口 控制user的动作接口 *  @remark */public interface IUserModel {    /*注册接口*/    boolean onRegister(String name,String passWord);    /*登陆接口*/    boolean onLogin(String name,String passWord);}

实现类 UserModel

/** * Created by MnyZhao on 2017/11/3. * model类 实现IUserModel中的动作接口 */public class UserModel implements IUserModel {    private Map<String, String> userMap = new HashMap<>();    /**     * 注册账号放入集合     *     * @param name     用户名     * @param passWord 密码     * @return 返回是否成功(true or false)     */    @Override    public boolean onRegister(String name, String passWord) {        if (!userMap.containsKey(name)) {            userMap.put(name, passWord);            return true;        }        return false;    }    /**     * 登陆接口     *     * @param name     用户名     * @param passWord 密码     * @return 是否登陆成功(true or false)     */    @Override    public boolean onLogin(String name, String passWord) {        return passWord.equals(userMap.get(name));    }}

3、现在我们要看看view了

ViewInterface 针对界面用户操作的相应接口

/** * Created by MnyZhao on 2017/11/3. */public interface IUserVIew {    //检查输入的合法性    boolean checkInputInfo();    //注册成功    void onRegisterSucceed();    //注册失败    void onRegisterFaild();    //登录成功    void onLoginSucceed();    //登录失败    void onLoginFaild();}

4、model view 都有了 我们就要Presenter了

Presenter类 用来沟通view 与model
所以要持有二者的接口对象

/** * Created by MnyZhao on 2017/11/3. */public class UserPresenter {    private IUserModel mUserModel;    private IUserVIew mIuserView;    public UserPresenter(IUserVIew mIuserView) {        this.mUserModel = new UserModel();        this.mIuserView = mIuserView;    }    public void registerUser(String name, String pwd) {        //根据Model中的结果调用不同的方法进行UI展示        if (mUserModel.onRegister(name, pwd)) {            mIuserView.onRegisterSucceed();        } else {            mIuserView.onRegisterFaild();        }    }    public void loginUser(String name, String pwd) {        //根据Model中的结果调用不同的方法进行UI展示        if (mUserModel.onLogin(name, pwd)) {            mIuserView.onLoginSucceed();        } else {            mIuserView.onLoginFaild();        }

5、接下来就要在activity(view)中实现了 需要实现view的接口(IUserVIew)并持有 Presenter的实例才能与view 进行交互

public class MainActivity extends AppCompatActivity implements IUserVIew {    private TextInputLayout mTilName;    private TextInputLayout mTilPassword;    private TextInputEditText mTieName;    private TextInputEditText mTiePassWord;    private Button mBtnRegister, mBtnLogin;    private UserPresenter userPeresenter;    private String name, pwd;    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_main);        initView();        initUserPersenter();    }    private void initView() {        mTilName = (TextInputLayout) findViewById(R.id.til_name);        mTilPassword = (TextInputLayout) findViewById(R.id.til_password);        mTieName = (TextInputEditText) findViewById(R.id.tie_name);        mTiePassWord = (TextInputEditText) findViewById(R.id.tie_password);        mBtnRegister = (Button) findViewById(R.id.btn_register);        mBtnLogin = (Button) findViewById(R.id.btn_login);        mBtnRegister.setOnClickListener(viewListener);        mBtnLogin.setOnClickListener(viewListener);    }    private View.OnClickListener viewListener = new View.OnClickListener() {        @Override        public void onClick(View v) {            switch (v.getId()) {                case R.id.btn_login:                    if (checkInputInfo()) {                        userPeresenter.loginUser(name, pwd);                    }                    break;                case R.id.btn_register:                    if (checkInputInfo()) {                        userPeresenter.registerUser(name, pwd);                    }                    break;            }        }    };    private void initUserPersenter() {        this.userPeresenter = new UserPresenter(this);    }    @Override    public boolean checkInputInfo() {        name = mTieName.getText().toString().trim();        pwd = mTiePassWord.getText().toString().trim();        if (("").equals(name)) {            mTilName.setError("Name is not null");            return false;        }        if (("").equals(pwd)) {            mTilPassword.setError("PassWord is not null");            return false;        }        return true;    }    @Override    public void onRegisterSucceed() {        Toast.makeText(this, "Register Successful", Toast.LENGTH_SHORT).show();    }    @Override    public void onRegisterFaild() {        Toast.makeText(this, "Register Error", Toast.LENGTH_SHORT).show();    }    @Override    public void onLoginSucceed() {        Toast.makeText(this, "Login Successful", Toast.LENGTH_SHORT).show();    }    @Override    public void onLoginFaild() {        Toast.makeText(this, "Login Error", Toast.LENGTH_SHORT).show();    }}

到此 代码详细无比 只要复制粘贴就能完美运行。。哦还少一些资源文件。。等我补上

drawable

<?xml version="1.0" encoding="UTF-8"?><shape    xmlns:android="http://schemas.android.com/apk/res/android"    android:shape="rectangle">    <!-- 填充的颜色 -->    <solid android:color="#63B8FF" />    <!-- 设置按钮的四个角为弧形 -->    <!-- android:radius 弧形的半径 -->    <corners android:radius="10px" />    <!-- padding:Button里面的文字与Button边界的间隔 -->    <padding        android:left="20px"        android:top="20px"        android:right="20px"        android:bottom="20px"        /></shape><?xml version="1.0" encoding="UTF-8"?><shape    xmlns:android="http://schemas.android.com/apk/res/android"    android:shape="rectangle">    <!-- 填充的颜色 -->    <solid android:color="#FFFFFF" />    <!-- 设置按钮的四个角为弧形 -->    <!-- android:radius 弧形的半径 -->    <corners android:radius="10px" />    <!-- padding:Button里面的文字与Button边界的间隔 -->    <padding        android:left="20px"        android:top="20px"        android:right="20px"        android:bottom="20px"        /></shape> 

xml

<?xml version="1.0" encoding="utf-8"?><LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"    xmlns:app="http://schemas.android.com/apk/res-auto"    xmlns:tools="http://schemas.android.com/tools"    android:layout_width="match_parent"    android:layout_height="match_parent"    android:orientation="vertical"    android:padding="10dp"    tools:context="com.mnyzhao.mymvpdemo.MainActivity">    <android.support.design.widget.TextInputLayout        android:id="@+id/til_name"        android:layout_width="match_parent"        android:layout_height="wrap_content"        android:textColorHint="@color/colorAccent"        app:errorTextAppearance="@color/colorPrimaryDark">        <android.support.design.widget.TextInputEditText            android:id="@+id/tie_name"            android:layout_width="match_parent"            android:layout_height="wrap_content"            android:hint="User"            android:textColor="@color/colorAccent"            android:textColorHint="@color/colorAccent" />    </android.support.design.widget.TextInputLayout>    <android.support.design.widget.TextInputLayout        android:id="@+id/til_password"        android:layout_width="match_parent"        android:layout_height="wrap_content"        android:layout_marginTop="20dp"        android:textColorHint="@color/colorAccent">        <android.support.design.widget.TextInputEditText            android:id="@+id/tie_password"            android:layout_width="match_parent"            android:layout_height="wrap_content"            android:hint="PassWord"            android:textColor="@color/colorAccent" />    </android.support.design.widget.TextInputLayout>    <LinearLayout        android:layout_width="match_parent"        android:layout_height="wrap_content"        android:layout_marginTop="20dp"        android:gravity="center"        android:orientation="horizontal"        android:paddingLeft="20dp"        android:paddingRight="20dp">        <Button            android:id="@+id/btn_register"            android:layout_width="match_parent"            android:layout_height="60dp"            android:layout_weight="1"            android:background="@drawable/whiteshape"            android:text="Register"            android:textAllCaps="false"            android:textColor="#63B8FF"            android:textSize="18sp" />        <Button            android:layout_width="30dp"            android:layout_height="wrap_content"            android:visibility="invisible" />        <Button            android:id="@+id/btn_login"            android:layout_width="match_parent"            android:layout_height="60dp"            android:layout_weight="1"            android:background="@drawable/blueshape"            android:text="Login"            android:textAllCaps="false"            android:textColor="@android:color/white"            android:textSize="18sp" />    </LinearLayout></LinearLayout>

如果你还不能运行 那 可能你缺少Material Design的包

compile 'com.android.support:design:25.+'

ok 如果还不行的话 那对不起 可能我不适合写代码………….

还是放上资源链接吧 不知道为什么 没有0积分的选项。。。
Demo