总体来说MVP就是通过一大堆接口回调拆分理清业务逻辑,从逻辑思维上达到简化代码项目的需求。
M----代表Model:对应于JavaBean,处理的是业务逻辑和实体模型
V-----代表View:对应于Activity,处理View的绘制和用户交互的操作
P-----代表presenter:这是新加的一个中间层,负责完成view和Model的交互
MVP的业务流程是,view与presenter相互交互,presenter操作model的数据,在View的绘制显示数据页面,View本身不再直接操作model层的数据实体而是通过presenter来控制
下面写一个登陆有关的小demo:
先看包结构:
1、User是一个JavaBean,代码如下:
package com.my_project.test_mvp.model;
/**
* Created by com_c on 2018/8/22.
*/
public class User {
private String userName;
private String password;
public User() {
}
public User(String userName, String password) {
this.userName = userName;
this.password = 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、UserLoginEvent是登陆的时候作出的业务操作,这个类放到Model层就是因为它是登录的业务类,根据类别的划分,业务逻辑和实体类JavaBean是放在model层里,那么登陆---当然就是拿到账号密码跑网络请求接口,代码如下
package com.my_project.test_mvp.model;
import com.my_project.test_mvp.model.User;
import com.my_project.test_mvp.presenter.IUserLogin;
import com.my_project.test_mvp.presenter.OnLoginListener;
/**
* Created by com_c on 2018/8/22.
*/
public class UserLoginEvent implements IUserLogin {
@Override
public void login(final String userName, final String pwd, final OnLoginListener onLoginListener) {
//开启子线程登录
new Thread() {
@Override
public void run() {
try {
Thread.sleep(2000);
} catch (Exception e) {
e.printStackTrace();
}
if (userName.equals("123") && pwd.equals("123")) {
onLoginListener.loginSuccess(new User(userName,pwd));
} else {
onLoginListener.loginFailed();
}
}
}.start();
}
}
3、登陆成功或者失败的接口回调
package com.my_project.test_mvp.presenter;
import com.my_project.test_mvp.model.User;
/**
* Created by com_c on 2018/8/22.
*/
public interface OnLoginListener {
void loginSuccess(User user);
void loginFailed();
}
view对应的就是Activity,MVP的规则是要通过presenter用model的数据来刷新view的界面,这就是说view不能自己去控制刷新的操作,而且,我们将login的访问服务器操作放在了model层,那用户输入的账号密码怎么传给model层,所以我们要在view层所在的activity中提供收集数据的方法,通过接口回调(也就是presenter的控制层)传给model层,在登录的这个模块中需要的方法有:
然后在跑网络请求的时候一般会给一个进度条的友好提醒,所以再加上
当用户输入账号密码要跳转下一个页面的时候,startActivity这一步当然说放在哪里都可以,不过跳转activity嘛,就在activity中实现代码应当是最合适的地方,也符合逻辑,所以再加两个登录成功与失败的方法
一般在登录页面会有一个一键清除输入框的取消按钮,所以我们一并实现两个清除账号密码的方法,接口的方法就是:
package com.my_project.test_mvp.view;
/**
* Created by com_c on 2018/8/22.
*/
public interface IUserLoginV {
String getUserName();
String getPassword();
void clearUserName();
void clearPassword();
void showLoading();
void hideLoading();
void toNextActivity();
void showFailedError();
}
这就是view的接口,这个view的接口是做什么用的?是给代表着View界面的activity实现做接口的,也就是说activity中的功能操作,view的接口都应该给出具体让activity实现的方法,比如说:
然后我们看下View接口的实现类,也就是activity的样子
package com.my_project.test_mvp.view;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.ProgressBar;
import android.widget.Toast;
import com.my_project.R;
import com.my_project.test_mvp.presenter.UserLoginPresenter;
/**
* Created by com_c on 2018/8/22.
*/
public class TestMVPActivity extends AppCompatActivity implements View.OnClickListener, IUserLoginV {
private EditText et_name, et_pwd;
private Button btn_commit, btn_clean;
private ProgressBar pBar;
private UserLoginPresenter userLoginPresenter = new UserLoginPresenter(this);
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_mvp);
bindID();
initView();
}
private void initView() {
btn_commit.setOnClickListener(this);
btn_clean.setOnClickListener(this);
}
private void bindID() {
et_name = findViewById(R.id.et_name);
et_pwd = findViewById(R.id.et_pwd);
btn_commit = findViewById(R.id.btn_commit);
btn_clean = findViewById(R.id.btn_clean);
pBar = findViewById(R.id.pBar);
}
@Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.btn_commit:
userLoginPresenter.login();
break;
case R.id.btn_clean:
userLoginPresenter.clean();
break;
}
}
@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 showLoading() {
pBar.setVisibility(View.VISIBLE);
}
@Override
public void hideLoading() {
pBar.setVisibility(View.GONE);
}
@Override
public void toNextActivity() {
Toast.makeText(TestMVPActivity.this, "成功跳转", Toast.LENGTH_SHORT).show();
}
@Override
public void showFailedError() {
Toast.makeText(TestMVPActivity.this, "账号密码有误", Toast.LENGTH_SHORT).show();
}
}
presenter是拿着model层的数据,去控制view层的显示,再结合现实中模块的功能,当前登录的话,就是一个login和clean
package com.my_project.test_mvp.presenter;
import com.my_project.test_mvp.model.OnLoginListener;
import com.my_project.test_mvp.model.UserLoginEvent;
import com.my_project.test_mvp.model.User;
import com.my_project.test_mvp.view.IUserLoginV;
/**
* Created by com_c on 2018/8/22.
*/
public class UserLoginPresenter {
private UserLoginEvent userLoginEvent;
private IUserLoginV userLoginView;
public UserLoginPresenter(IUserLoginV iUserLoginV) {
this.userLoginView = iUserLoginV;
this.userLoginEvent = new UserLoginEvent();
}
private android.os.Handler mHandler = new android.os.Handler();;
public void login() {
userLoginView.showLoading();
userLoginEvent.login(userLoginView.getUserName(), userLoginView.getPassword(), new OnLoginListener() {
@Override
public void loginSuccess(User user) {
mHandler.post(new Runnable() {
@Override
public void run() {
userLoginView.toNextActivity();
userLoginView.hideLoading();
}
});
}
@Override
public void loginFailed() {
mHandler.post(new Runnable() {
@Override
public void run() {
userLoginView.showFailedError();
userLoginView.hideLoading();
}
});
}
});
}
public void clean() {
userLoginView.clearUserName();
userLoginView.clearPassword();
}
}
可以看到,我们是在Activity中引用这个presenter层的,也就是View层调用presenter层,那么presenter层去model层拿数据在哪里体现,presenter层的构造方法中拿到了用户在activity输入的账号密码,这是View层的接口提供给presenter的数据,而这些账号密码的数据又通通传递给了model层去做业务逻辑的操作,也就是model层中跑服务器接口,去真正login(),然后登录成功与否的反馈,又是通过model层调用去触发登录的接口回调,而在presenter层实现这个接口,presenter层拿到了接口回调的结果之后,再去触发View层的接口回调,这时候,View层(也就是Activity)实现了这个接口方法,拿到方法再去执行对应的操作,