android中MVP或者说mvp模式的使用及思想分解,mvp和mvc的区别

1,首先,什么是mvp模式?为什么使用mvp?


(官方描述:)

关于mvp模式,可以这样认识他,随着UI创建技术的功能日益增强,UI层(可以粗略理解为activity页面,如果你不理解的话)也履行着越来越多的职责。为了更好地细分视图(View)与模型(Model)的功能,让View专注于处理数 据的可视化以及与用户的交互,同时让Model只关系数据的处理,基于MVC概念的MVP(Model-View-Presenter)模式应运而生。


在Android开发中,Activity并不是一个标准的MVC模式中的Controller,它 的首要职责是加载应用的布局和初始化用户界面,并接受并处理来自用户的操作请求,进而作出响应。随着界面及其逻辑的复杂度不断提升,Activity类的 职责不断增加,以致变得庞大臃肿。当我们将其中复杂的逻辑处理移至另外的一个类(Presneter)中时,Activity其实就是MVP模式中 View,它负责UI元素的初始化,建立UI元素与Presenter的关联(Listener之类),同时自己也会处理一些简单的逻辑(复杂的逻辑交由 Presenter处理).




(个人描述:)
总结为一句话:
为了让安卓中的ui部分减少数据处理数量,将压力减低,让其他的部分帮他分解压力,这样说懂了吧?



2,那么,mvp模式是如何进行设计与联系的呢?






     (1)View:负责绘制UI元素、与用户进行交互(在Android中体现为Activity);


     (2)View interface:需要View实现的接口,View通过View interface与Presenter进行交互,降低耦合,方便进行单元测试;


     (3)Model:负责存储、检索、操纵数据(有时也实现一个Model interface用来降低耦合);


     (4)Presenter:作为View与Model交互的中间纽带,处理与用户交互的负责逻辑。




他们之间的关系可以这么看:


首先分别介绍一下他们三个如何操作与使用的


   先说View,View你可以理解为activity他是用来进行ui界面绘制的,一般情况下都会单独建一个view接口,让activity来实现他,实现的目的是什么,是用来到后边进行接口回调数据使用的。


这里我从工程中粗略的切了几张图,残缺不全,大家可以就当个意思,看的明白就行了;


如图:

这是活动继承了view,这里的activity就可以被认为ui界面,可以被叫做view,


 

/**
 * MVC   M  model 实体模型业务类   V 视图    C 控制器
 *
 * MVP(Model View Presenter)
 *  view 通常activity或者fragment或者某个控件  负责view的绘制和用户交互
 *  model 业务逻辑和实体模式  提供数据的存取功能
 *  Presenter 负责view和model层之间的交互  中间人 降低view层model层之间的耦合度
 *
 * MVP模式的好处:
 * 1.降低view层model层之间的耦合度 降低了view的复杂性 提高了可拓展性
 *
 * MVC和MVP之间的区别?
 *   MVC模式中允许model层和view层之间进行交互;MVP中 model和view之间交互由Presenter
 * 完成
 *  MVVM 与MVP类似 唯一的区别就是view与model双向绑定 两者之间一方放生变化则会影响到另一方
 *  MVVM与AdapterView与adapter的关系类型
 */
public class MainActivity extends AppCompatActivity implements
        IUserLoginView{
    private EditText et_name,et_pwd;
    private UserLoginPresenter presenter=new UserLoginPresenter(this);
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        et_name= (EditText) findViewById(R.id.et_userName);
        et_pwd= (EditText) findViewById(R.id.et_password);
        findViewById(R.id.btn_login).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                presenter.login();
            }
        });

        findViewById(R.id.btn_clear).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                presenter.clear();
            }
        });

    }

    @Override
    public String getUserName() {
        return et_name.getText().toString().trim();
    }

    @Override
    public String getPassword() {
        return et_pwd.getText().toString().trim();
    }

    @Override
    public void clearUserName() {
        et_name.setText("");
    }

    @Override
    public void clearPassword() {
        et_pwd.setText("");
    }

    @Override
    public void loginSucess(User user) {
        Toast.makeText(this,user.getUserName()+"登录成功!",Toast.LENGTH_LONG).show();
    }

    @Override
    public void showFailed() {
        Toast.makeText(this,"登录失败!",Toast.LENGTH_LONG).show();
    }
}

//这是view接口,提供了很多方法用来得到model中传递过来的数据,你在做界面操作的时候想一下你需要让界面作什么,就在这个view接口中声明一个抽象方法,在这里我让view做的事情是

得到用户姓名,

得到用户密码,

清除用户姓名,

清除用户密码,成功失败操作,

这里先不管,接着往下看:


/**
 * 定义view层的接口  接口中定义什么函数?
 * 观察界面需要展示什么信息  接口中定义什么函数向activity中进行展示
 */
public interface IUserLoginView {
    //界面需要对view视图做什么操作都定义在该接口中
    //实现登录功能时需要获取用户名和密码
    public String getUserName();
    public String getPassword();

    //重置时需要清除用户名和密码
    public void clearUserName();
    public void clearPassword();

    //点击登录按钮时成功或者失败的情况
    public void loginSucess(User user);
    public void showFailed();
}



再说一下model,他是一个具体的进行逻辑编写操作的类,如果需要也可以给model也创建一个接口,让model来继承;

这个接口决定了,子类要进行的工作,具体的逻辑 操作和运算就是去登陆界面,

**
 * model中的接口 业务逻辑类 抽取的接口 定义的业务逻辑类的方法
 */
public interface IUserBiz {
    public void login(String userName,String passWord,
                      OnLoginListener loginListener);
}




这里在model的接口中写了接口,实现此接口用来进行具体的逻辑操作,此处的model实现了model的抽象方法,里面我模拟了一个具体的登陆操作,这里用一个耗时睡眠代替,毕竟只是个demo我也犯不上去登陆别的服务器吧,哈哈,这个代码还会少些。不是么

/**
 * model层的具体的业务逻辑类
 */
public class UserBiz implements IUserBiz{
    //实现登录的具体的业务逻辑
    @Override
    public void login(final String userName, final String passWord,
                      final OnLoginListener loginListener) {
        new Thread(new Runnable() {
            @Override
            public void run() {
                //工作线程模拟耗时操作 登录联网获取具体结果
                try {
                    Thread.sleep(2000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }

                if("admin".equals(userName) && "admin".equals(passWord)){
                    User user=new User();
                    user.setUserName(userName);
                    user.setPassword(passWord);
                    loginListener.loginSuccess(user);
                }else{
                    loginListener.loginFaied();
                }
            }
        }).start();
    }
}

另外,单独做一个接口回调:如果登陆成功的话就将user对象传递出去,

/**
 * 登录操作的接口 登录操作完成的结果
 * 登录成功 登录失败的回调函数
 */
public interface OnLoginListener {
    public void loginSuccess(User user);
    public void loginFaied();
}

对了,这里还得写一个user的bean类,这个是个人demo需求,不是必须有的:

/**
 * 将用户名和密码封装到用户实体类中
 */
public class User {
    private String userName;
    private String password;

    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;
    }
}




再说一下Presenter:
他的作用非常简单,他通过调用model中的方法,将model逻辑操作的数据通过activit的接口回调方式将数据结果传回到activtiy中,你可以理解为,工人model打工结束后,presenter将工人的劳动果实带给activity,
他们之间的关系就是老板(activity),工人(model),(使者或者说项目经理)的关系,


View不直接与Model交互,而是通过与Presenter交互来与Model间接交互
Presenter与View的交互是通过接口来进行的,更有利于添加单元测试
通常View与Presenter是一对一的,但复杂的View可能绑定多个Presenter来处理逻辑 



//presenter的实现类:本来如果工程量比较大的话Presenter也需要和上边一样创建抽象类的,毕竟这个鄙不是必须的,索性不添加了。免得你又会觉得凌乱;


/**
 * 中间人类 访问model和view
 */
public class UserLoginPresenter {
    private IUserBiz userBiz;//model业务逻辑层
    private IUserLoginView userLoginView;//view视图层
    //定义构造函数  IUserLoginView userLoginView=activity;
    public UserLoginPresenter(IUserLoginView userLoginView){
        this.userLoginView=userLoginView;
        this.userBiz=new UserBiz();//IUserBiz userBiz=new UserBiz();
    }

    Handler handler=new Handler();
//中间人操作登录功能 中间人访问业务逻辑层model层中的业务---结果展示到view层
    public void login(){
        //userBiz.login()中间人访问 model业务逻辑层的函数
        //login()方法参数由view视图层提供
        userBiz.login(userLoginView.getUserName(),
                userLoginView.getPassword(),
                new OnLoginListener() {
            @Override
            public void loginSuccess(final User user) {
                //提醒页面登录成功
                handler.post(new Runnable() {
                    @Override
                    public void run() {
                        userLoginView.loginSucess(user);
                    }
                });

            }

            @Override
            public void loginFaied() {
                handler.post(new Runnable() {
                    @Override
                    public void run() {
                        userLoginView.showFailed();
                    }
                });
            }
        });
    }
//重置
    public void clear(){
      userLoginView.clearUserName();
      userLoginView.clearPassword();
    }


}

 如果有需要的大家可以参考一下运行以下结果,对了,这里把布局也直接补上吧:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    tools:context="com.yztc.mvpdemo.MainActivity"
    android:orientation="vertical">

    <EditText
        android:id="@+id/et_userName"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:hint="请输入用户名"
        android:textSize="25sp"/>
    <EditText
        android:id="@+id/et_password"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:hint="请输入密码"
        android:inputType="textPassword"
        android:textSize="25sp"/>
    <Button
        android:id="@+id/btn_login"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="登录"
        android:textSize="20sp"/>
    <Button
        android:id="@+id/btn_clear"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="重置"
        android:textSize="20sp"/>
</LinearLayout>




写到这里或许你对mvp有了一些认识,但是mvp是从mvc繁衍过来的,为什么会出现mvp那是因为mvc模式不能够很好的将view和model进行分离,

你会问,什么是mvc?

mvc就是model view controller,意思和mvp差不多,但是两者的区别就是,view和model是可以直接进行交互的,而mvp中两者的交互使用prosster当了中间人,这样更好的将view和mldel进行了隔离。

 


发布了39 篇原创文章 · 获赞 14 · 访问量 4万+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章