摘要
以登录为例子,对比使用MVP与不使用的区别。
不使用MVP,模拟登录场景
public class LoginActivity extends Activity implements View.OnClickListener {
private EditText mAccountInput;
private EditText mPassowrdInput;
private Button mLoginBtn;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_login);
// 绑定控件,设置监听
mAccountInput = (EditText) findViewById(R.id.input_account);
mPassowrdInput = (EditText) findViewById(R.id.input_password);
mLoginBtn = (Button) findViewById(R.id.btn_login);
mLoginBtn.setOnClickListener(this);
}
@Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.btn_login:
doLogin(mAccountInput.getText().toString(), mPassowrdInput.getText().toString());
break;
default:
break;
}
}
/**
* 执行登录
* @param mAccount �账号
* @param mPassword 密码
*/
private void doLogin(String mAccount, String mPassword) {
if (TextUtils.isEmpty(mAccount) || TextUtils.isEmpty(mPassword))
doLoginFail("账号与密码不能为空");
// 模拟登录过程的异步
new AsyncTask<Void, Void, LoginInfo>() {
@Override
protected void onPreExecute() {
super.onPreExecute();
showLoading()
}
@Override
protected LoginInfo doInBackground(Void... params) {
// TODO: 网络请求,这里直接模拟返回登录结果
return new LoginInfo();
}
@Override
protected void onPostExecute(LoginInfo loginInfo) {
super.onPostExecute(loginInfo);
dismissLoading()
if (loginInfo.isSuccess()) {
doLoginSuccess(loginInfo);
} else {
doLoginFail(loginInfo.getErrorMessage());
}
}
}.execute();
}
/**
* 显示等待提示
*/
private void showLoading() {
// TODO: 显示等待提示
}
/**
* 隐藏等待提示
*/
private void dismissLoading() {
// TODO: 隐藏等待提示
}
/**
* 登录成功
* @param mLoginInfo 登录信息
*/
private void doLoginSuccess(LoginInfo mLoginInfo) {
// TODO: 执行登录成功逻辑
}
/**
* 登录失败
* @param errorMessage 失败提示
*/
private void doLoginFail(String errorMessage) {
// TODO: 显示错误信息
}
}
使用MVP,模拟登录场景
定义Model
public interface LoginModel {
/**
* 执行登录操作
* @param mAccount 账号
* @param mPassword 密码
* @param mLoginListener
*/
void doLogin(String mAccount, String mPassword, OnLoginListener mLoginListener);
/**
* 登录异步回调
*/
interface OnLoginListener {
void finishLogin(LoginInfo mLoginInfo);
}
}
public class LoginModelImpl implements LoginModel {
@Override
public void doLogin(String mAccount, String mPassword, final OnLoginListener mLoginListener) {
if (TextUtils.isEmpty(mAccount) || TextUtils.isEmpty(mPassword)) {
LoginInfo mLoginInfo = new LoginInfo();
mLoginInfo.setSuccess(false);
mLoginInfo.setErrorMessage("账号与密码不能为空");
mLoginListener.finishLogin(mLoginInfo);
return ;
}
// 模拟登录过程的异步
new AsyncTask<Void, Void, LoginInfo>() {
@Override
protected LoginInfo doInBackground(Void... params) {
// TODO: 网络请求,这里直接模拟返回登录结果
return new LoginInfo();
}
@Override
protected void onPostExecute(LoginInfo loginInfo) {
super.onPostExecute(loginInfo);
mLoginListener.finishLogin(loginInfo);
}
}.execute();
}
}
定义Presenter
public interface LoginPresenter {
/**
* 执行登录操作
* @param mAccount 账号
* @param mPassword 密码
*/
void doLogin(String mAccount, String mPassword);
}
public class LoginPresenterImpl implements LoginPresenter {
private LoginView mLoginView;
private LoginModel mLoginModel;
public LoginPresenterImpl(LoginView mLoginView, LoginModel mLoginModel) {
this.mLoginView = mLoginView;
this.mLoginModel = mLoginModel;
}
@Override
public void doLogin(String mAccount, String mPassword) {
mLoginView.showLoading();
mLoginModel.doLogin(mAccount, mPassword, new LoginModel.OnLoginListener() {
@Override
public void finishLogin(LoginInfo mLoginInfo) {
mLoginView.dismissLoading();
if (mLoginInfo.isSuccess()) {
mLoginView.loginSuccess(mLoginInfo);
} else {
mLoginView.loginFail(mLoginInfo.getErrorMessage());
}
}
});
}
}
定义View
public interface LoginView {
/**
* 显示等待提示
*/
void showLoading();
/**
* 隐藏等待提示
*/
void dismissLoading();
/**
* 登录成功
* @param mLoginInfo 登录信息
*/
void loginSuccess(LoginInfo mLoginInfo);
/**
* 登录失败
* @param errorMessage 失败提示
*/
void loginFail(String errorMessage);
}
public class LoginActivity extends Activity implements View.OnClickListener, LoginView {
private EditText mAccountInput;
private EditText mPassowrdInput;
private Button mLoginBtn;
private LoginPresenter mLoginPresenter;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_login);
mLoginPresenter = new LoginPresenterImpl(this, new LoginModelImpl());
// 绑定控件,设置监听
mAccountInput = (EditText) findViewById(R.id.input_account);
mPassowrdInput = (EditText) findViewById(R.id.input_password);
mLoginBtn = (Button) findViewById(R.id.btn_login);
mLoginBtn.setOnClickListener(this);
}
@Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.btn_login:
String mAccount = mAccountInput.getText().toString();
String mPassword = mPassowrdInput.getText().toString();
mLoginPresenter.doLogin(mAccount, mPassword);
break;
default:
break;
}
}
@Override
public void showLoading() {
// TODO: 显示等待提示
}
@Override
public void dismissLoading() {
// TODO: 隐藏等待提示
}
@Override
public void loginSuccess(LoginInfo mLoginInfo) {
// TODO: 执行登录成功逻辑
}
@Override
public void loginFail(String errorMessage) {
// TODO: 显示错误信息
}
}
个人理解
- MVP会增加代码量,是事实。
- MVP能减轻Activity/Fragment的臃肿程度。
- 当Activity/Fragment存在更多的逻辑,虽然增加代码量,但开发效率更高。
- 架构不是编码规范,不是组织代码规范,是一种思维方式。
- 思维清晰,打代码自然一马平川。
- MVP易于单元测试。
无穷的思考
- 一个Activity对应一个Fragment,由Fragment负责View的职责。
- Activity仅仅管理生命周期,管理MVP三者的实例化和三者的引用关系。
- Activity是上帝。
- 这样更加贴合MVP的�概念。
最后
要概念上的合理,还是现实中的方便,其实都可以,见仁见智。