项目结构图
GitHub地址:https://github.com/yangtianfu2018/MVPDemo
本例就是简单的登录页面,获取用户名和密码登录,只不过用MVP的架构去实现,所以效果就不展示了
MVP搭建步骤:
1Javabean实体类
package com.ytflogin.mvp.bean;
import android.os.Parcel;
import android.os.Parcelable;
import java.io.Serializable;
/**
* step①
* Created by ppg on 2018/2/26.
*/
public class UserBean implements Serializable{// Parcelable
private String name;
private String pwd;
public UserBean() {
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getPwd() {
return pwd;
}
public void setPwd(String pwd) {
this.pwd = pwd;
}
// @Override
// public int describeContents() {
// return 0;
// }
//
// @Override
// public void writeToParcel(Parcel dest, int flags) {
// dest.writeString(name);
// dest.writeString(pwd);
// }
}
2 View层从页面获取数据
package com.ytflogin.mvp.view;
/**
* step②
* Created by ytf on 2018/2/26.
* 一个页面对应一个view层接口,提供获取数据的方法
* View层的任务就是抽象页面的数据,提取出来写成方法
*/
public interface IUserView {
// 提供获取用户名和密码信息的数据接口方法
public String getUserName();
public String getPwd();
}
3 Model层的登录的监听接口
package com.ytflogin.mvp.model;
/**
* step③
* Created by ytf on 2018/2/26.
* 处理业务逻辑的监听接口,这里用来判断登陆结果状态
*/
public interface IUserLoginListenser {
// 用来监听业务逻辑处理的判断,实现接口后可以通过Toast等显示结果
public void onSucess();//登陆成功
public void onError();//用户信息不正确
public void onFail();//登陆失败
}
4 Model层业务处理接口
package com.ytflogin.mvp.model;
/**
* step④
* Created by ytf on 2018/2/26.
* 提供处理数据的接口方法,这里封装一个登陆的方法,
*/
public interface IUserModel {
/**
* 提取一个登陆的方法,并传入登陆监听接口,也可以添加别的方法
* @param name 用户名
* @param pwd 用户密码
* @param userLoginListenser 登陆状态监听
*/
public void login(String name,String pwd,IUserLoginListenser userLoginListenser);
}
5 Model层业务处理的实现类
package com.ytflogin.mvp.model;
import android.text.TextUtils;
/**
* step⑤ 实现登陆接口的方法,处理业务逻辑
* Created by ytf on 2018/2/26.
*/
public class UserModel implements IUserModel {
@Override
public void login(String name, String pwd, IUserLoginListenser userLoginListenser) {
if(TextUtils.isEmpty(name)||TextUtils.isEmpty(pwd)){
userLoginListenser.onError();
return;
}
if (name.equals("ytf")&&pwd.equals("123")){
userLoginListenser.onSucess();
}else {
userLoginListenser.onFail();
}
}
}
6 Presenter层关联Model层和View层
package com.ytflogin.mvp.presenter;
import com.ytflogin.mvp.model.IUserLoginListenser;
import com.ytflogin.mvp.model.IUserModel;
import com.ytflogin.mvp.model.UserModel;
import com.ytflogin.mvp.view.IUserView;
/**
* step⑥
* view层中提供数据源,model层提供业务逻辑方法,
* presenter就是要把他们关联起来,所以需要model和view的实例
* Created by ytf on 2018/2/26.
*/
public class IUserPresenter {
// 数据源,view的实例:
private IUserView iUserView;
// 业务逻辑,model实例
private IUserModel iUserModel;//父类的引用
/**
* 构造方法,传入view层数据源
* @param iUserView
*/
public IUserPresenter(IUserView iUserView) {
this.iUserView = iUserView;
iUserModel=new UserModel();//父类引用指向子类对象,调用登录方法
}
/**
* 登录的方法,把view层和model层建立关联,实现真正的登录
* @param loginListenser
*/
public void login(IUserLoginListenser loginListenser){
iUserModel.login(iUserView.getUserName(),iUserView.getPwd(),loginListenser);
}
}
7 acvitity中用Presenter实例实现数据与模型交互
package com.ytflogin.mvp.activitity;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.ImageView;
import android.widget.Toast;
import com.ytflogin.mvp.R;
import com.ytflogin.mvp.model.IUserLoginListenser;
import com.ytflogin.mvp.presenter.IUserPresenter;
import com.ytflogin.mvp.view.IUserView;
import butterknife.BindView;
public class MainActivity extends AppCompatActivity implements IUserView{//实现view层接口从页面获取数据源
//step ⑦这里使用了butterknife注解方式,省去了findviewbyid的操作
@BindView(R.id.et_name)
EditText et_name;
@BindView(R.id.et_pwd)
EditText et_pwd;
@BindView(R.id.btn_login)
Button btn_login;
private IUserPresenter userPresenter;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
userPresenter=new IUserPresenter(this);
btn_login.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
userPresenter.login(loginListenser);
}
});
}
/**
* 实例化登录监听接口
*/
private IUserLoginListenser loginListenser=new IUserLoginListenser() {
@Override
public void onSucess() {
Toast.makeText(getApplication(),"登录成功!",Toast.LENGTH_SHORT).show();
}
@Override
public void onError() {
Toast.makeText(getApplication(),"信息不全!",Toast.LENGTH_SHORT).show();
}
@Override
public void onFail() {
Toast.makeText(getApplication(),"登录失败!",Toast.LENGTH_SHORT).show();
}
};
/**
* 以下方法获取页面数据
* @return 用户输入数据
*/
@Override
public String getUserName() {
return et_name.getText().toString();
}
@Override
public String getPwd() {
return et_pwd.getText().toString();
}
}
流程图解:
MVP与MVC的区别:
MVC框架:everything is connected with Activity
view: 视图层,对应与xml布局文件
model: 模型层,对应业务逻辑和实体类
controller: 控制层,对应acvitity
缺点:view视图层对应xml布局文件,所做的事情相当有限,布局文件中的事件绑定,数据处理都是在acvitity中进行
造成acvitity既像view又像controller、MVP框架:
view: 视图层,对应acvitity,负责view的绘制和用户交互,View层的任务就是抽象页面的数据,提取出来写成方法(接口中的方法),就是获取数据
model: 依然是业务逻辑和实体类,提供处理数据的方法,也是接口,还有实现接口的类
presenter: 负责完成view和model之间的交互
特点:代码结构更清晰,减少了acvitity的职责,简化了acvitity中的代码,不再是everything is connected with Acvitity
将复杂的逻辑代码提取到了Presenter类中执行,让model和view完全解耦,耦合度更低区别:①MVC中是允许model和view进行交互的,而MVP中是不允许的,model和view都是通过Presenter这个类进行数据交互
②presenter和view的交互是通过接口完成的
③在MVP中视图的渲染放在了Presenter中,使得view和presenter交互会比较频繁,如果二者联系比较紧密,那么当view中数据改变时,presenter有可能也要做相应改变。