(官方描述:)
关于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进行了隔离。