浅谈Android中的MVP
程序员文章站
2024-03-15 19:28:36
...
MVP简介
现在所做的项目中大部分的功能都同UI混合在一起,导致代码的耦合性比较查,代码逻辑比较混乱,为了更好地细分视图(View)与模型(Model)的功能,让View专注于处理数据的可视化以及与用户的交互,同时让Model只关系数据的处理,基于MVC概念的MVP(Model-View-Presenter)模式应运而生。
在MVP模式里通常包含4个要素:
- View:负责绘制UI元素、与用户进行交互(在Android中体现为Activity);
- View interface:需要View实现的接口,View通过View interface与Presenter进行交互,降低耦合,方便进行单元测试;
- Model:负责存储、检索、操纵数据(有时也实现一个Model interface用来降低耦合);
- Presenter:作为View与Model交互的中间纽带,处理与用户交互的负责逻辑;
MVC和MVP区别
- 用户 Event(事件)会导致 Controller 改变 Model 或 View 或同时改变两者。
- 只要 Controller 改变了 Model 的数据或属性,所有依赖的 View 都会自动更新。
- 类似的,只要 Controller 改变了 View ,View 会从潜在的 Model 中获取数据进行更新。
- Presenter 中同时持有 View 以及 Model 的 Interface 引用,而 View 持有 Presenter 的实例。
- 当某个 View 需要展示某些数据时,首先会调用 Presenter 的某个接口,然后 Presenter 会调用 Model 请求数据。
- 当 Model 数据加载成功后会调用 Presenter 的回调方法通知 Presenter 数据加载完毕,最后 Presenter 再调用 View 层接口展示加载后数据。
主要区别
MVC:
- View 可以与 Model 直接交互;
- Controller 可以被多个 View 共享;
- Controller 可以决定显示哪个 View;
MVP:
- View 不直接与 Model 交互;
- Presenter 与 View 通过接口来交互,更有利于添加单元测试;
- 通常 View 与 Presenter 是一对一的,但复杂的 View 可能绑定多个 Presenter 来处理;
- Presenter 也可以直接进行 View 上的渲染。
示例
(1)登录示例
(1)Bean实体类
public class LoginBean {
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;
}
}
(2)Model接口
public interface ILoginModel {
public void login(String username, String password, OnLoginListener onLoginListener);
}
(3)Model实体类
public class LoginModel implements ILoginModel {
@Override
public void login(final String username, final String password, final OnLoginListener onLoginListener) {
new Thread(new Runnable() {
@Override
public void run() {
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
if ("dong".equals(username) && "123".equals(password)) {
LoginBean bean = new LoginBean();
bean.setUsername(username);
bean.setPassword(password);
onLoginListener.loginSuccess(bean);
} else {
onLoginListener.loginFailed();
}
}
}).start();
}
}
(4)接口回调处理
public interface OnLoginListener {
public void loginSuccess(LoginBean bean);
public void loginFailed();
}
(5)View接口
public interface ILoginView {
public String getUserName();
public String getPassWord();
public void showLoading();
public void hideLoading();
public void dealLoadSuccess(LoginBean bean);
public void dealLoadFailed();
public void clearUserName();
public void clearPassWord();
}
(6)Presenter实体类
public class LoginPresenter {
private ILoginModel loginModel;
private ILoginView loginView;
private Activity mMainActivity;
public LoginPresenter(ILoginView loginView, Activity mActivity) {
this.loginView = loginView;
mMainActivity = mActivity;
loginModel = new LoginModel();
}
public void login() {
loginView.showLoading();
loginModel.login(loginView.getUserName(), loginView.getPassWord(), new OnLoginListener() {
//这里还是子线程中
@Override
public void loginSuccess(final LoginBean bean) {
mMainActivity.runOnUiThread(new Runnable() {
@Override
public void run() {
loginView.hideLoading();
loginView.dealLoadSuccess(bean);
}
});
}
@Override
public void loginFailed() {
mMainActivity.runOnUiThread(new Runnable() {
@Override
public void run() {
loginView.hideLoading();
loginView.dealLoadFailed();
}
});
}
});
}
public void clear() {
loginView.clearUserName();
loginView.clearPassWord();
}
}
(7)View的实体类
public class LoginActivity extends AppCompatActivity implements View.OnClickListener, ILoginView {
private EditText username, password;
private ProgressBar progress;
private LoginPresenter presenter;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.login_activity);
username = (EditText) findViewById(R.id.username);
password = (EditText) findViewById(R.id.password);
progress = (ProgressBar) findViewById(R.id.progress);
findViewById(R.id.login).setOnClickListener(this);
findViewById(R.id.clear).setOnClickListener(this);
presenter = new LoginPresenter(this, this);
}
@Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.login:
presenter.login();
break;
case R.id.clear:
presenter.clear();
break;
}
}
@Override
public String getUserName() {
return username.getText().toString();
}
@Override
public String getPassWord() {
return password.getText().toString();
}
@Override
public void showLoading() {
progress.setVisibility(View.VISIBLE);
}
@Override
public void hideLoading() {
progress.setVisibility(View.GONE);
}
@Override
public void dealLoadSuccess(LoginBean bean) {
Toast.makeText(this, bean.getUsername() + " login success", Toast.LENGTH_SHORT).show();
}
@Override
public void dealLoadFailed() {
Toast.makeText(this, "login failed", Toast.LENGTH_SHORT).show();
}
@Override
public void clearUserName() {
username.setText("");
}
@Override
public void clearPassWord() {
password.setText("");
}
}
(2)注册登录示例
(1)Bean实体类
public class PersonBean {
private String name;
private String pwd;
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;
}
}
(2)Model接口
public interface IPersonModel {
public boolean register(String name, String pwd);
public boolean login(String name, String pwd);
}
(3)Model实体类
public class PersonModel implements IPersonModel {
private Map<String, String> personMap = new HashMap<>();
@Override
public boolean register(String name, String pwd) {
if (!personMap.containsKey(name)) {
personMap.put(name, pwd);
return true;
}
return false;
}
@Override
public boolean login(String name, String pwd) {
return pwd.equals(personMap.get(name));
}
}
(4)View接口
public interface IPersonView {
public boolean checkInputInfo();
public void registerSuccess();
public void registerFailed();
public void loginSuccess();
public void loginFailed();
}
(5)Presenter实体类
public class PersonPresenter {
private IPersonModel personModel;
private IPersonView personView;
public PersonPresenter(IPersonView personView) {
this.personView = personView;
personModel = new PersonModel();
}
//注册
public void register(String name, String pwd) {
boolean isRegister = personModel.register(name, pwd);
if (isRegister) {
personView.registerSuccess();
} else {
personView.registerFailed();
}
}
//登录
public void login(String name, String pwd) {
boolean isLogin = personModel.login(name, pwd);
if(isLogin){
personView.loginSuccess();
}else{
personView.loginFailed();
}
}
}
(6)View的实体类
public class PersonActivity extends AppCompatActivity implements View.OnClickListener, IPersonView {
private EditText name, pwd;
private String inputName, inputPwd;
private PersonPresenter mPresenter;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.person_activity);
name = (EditText) findViewById(R.id.username);
pwd = (EditText) findViewById(R.id.password);
findViewById(R.id.login).setOnClickListener(this);
findViewById(R.id.register).setOnClickListener(this);
mPresenter = new PersonPresenter(this);
}
@Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.login:
if (checkInputInfo()) {
mPresenter.login(inputName, inputPwd);
}
break;
case R.id.register:
if (checkInputInfo()) {
mPresenter.register(inputName, inputPwd);
}
break;
}
}
@Override
public boolean checkInputInfo() {
inputName = name.getText().toString();
inputPwd = pwd.getText().toString();
if ("".equals(inputName)) {
Toast.makeText(this, "用户名不能为空", Toast.LENGTH_SHORT).show();
return false;
}
if ("".equals(inputPwd)) {
Toast.makeText(this, "密码不能为空", Toast.LENGTH_SHORT).show();
return false;
}
return true;
}
@Override
public void registerSuccess() {
Toast.makeText(this, "注册成功", Toast.LENGTH_SHORT).show();
}
@Override
public void registerFailed() {
Toast.makeText(this, "注册失败", Toast.LENGTH_SHORT).show();
}
@Override
public void loginSuccess() {
Toast.makeText(this, "登录成功", Toast.LENGTH_SHORT).show();
}
@Override
public void loginFailed() {
Toast.makeText(this, "登录失败", Toast.LENGTH_SHORT).show();
}
}
好啦,MVP的简单介绍就到这里了。