MVC --> MVP :
将Activity的View和Controller双重职责分离,Activity单纯负责View逻辑,Presenter层处理Model和View层的所有逻辑,Model层处理纯数据。
换言之,MVP类似于MVC++,解决分离不彻底的问题。
同时MVP也有一些值得讨论的地方:
- Presenter层与View层是通过接口进行交互,接口粒度控制存在问题。粒度小,接口量过大;粒度大,单一职能性不好。
- Presenter只是解决了功能分离的问题,复杂业务单个类代码臃肿问题,仍需要分离多个Presenter - View处理同一个复杂页面。
瑕不掩瑜,MVP仍然是很好的一套Android前端框架。
文件结构如下:
当然实际项目中不可能这样分包,这里只是单纯MVP结构划分的效果。
M、V、P 接口以及具体的实现
Model:这里只有处理登录接口。持有Presenter
package com.example.mvpdemo.model;
/**
* Model层 数据逻辑处理
*/
public interface IUserBiz {
void login(String username, String password);
}
package com.example.mvpdemo.model;
import com.example.mvpdemo.bean.UserBean;
import com.example.mvpdemo.presenter.ILoginPresenter;
/**
* Model层 具体的数据交互实现,也单纯包含数据,不包含逻辑
*/
public class UserBiz implements IUserBiz {
private ILoginPresenter mPresenter;
public UserBiz(ILoginPresenter mPresenter) {
this.mPresenter = mPresenter;
}
@Override
public String login(String username, String password) {
// 接口调用,返回数据
return login(username,password);
}
}
View:对应登录UI,页面的不同效果,以及获取页面数据。持有Presenter
package com.example.mvpdemo.view;
import com.example.mvpdemo.bean.UserBean;
/**
* View层 分离UI逻辑
*/
public interface ILoginView {
void toSuccessPage(UserBean user);
void showErrMessage(String message);
}
/**
* View层 处理ui逻辑
*/
public class MainActivity extends AppCompatActivity implements ILoginView {
private EditText mEtUsername;
private EditText mEtPassword;
private Button mBtnLogin;
private LoginPresenter mLoginPrinter = new LoginPresenter(this);
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
findViews();
}
private void findViews() {
mEtUsername = (EditText) findViewById(R.id.editText2);
mEtPassword = (EditText) findViewById(R.id.editText);
mBtnLogin = (Button) findViewById(R.id.button);
mBtnLogin.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
mLoginPrinter.login(getUserName(), getPassword());
showLoading();
}
});
}
public String getUserName() {
return mEtUsername.getText().toString();
}
public String getPassword() {
return mEtPassword.getText().toString();
}
public void showLoading() {
Toast.makeText(this, "开始转菊花", Toast.LENGTH_SHORT).show();
}
public void hideLoading() {
Toast.makeText(this, "结束转菊花", Toast.LENGTH_SHORT).show();
}
@Override
public void toSuccessPage(UserBean userBean) {
hideLoading();
Toast.makeText(this, userBean.getUsername() + "跳转去主页面", Toast.LENGTH_SHORT).show();
}
@Override
public void showErrMessage(String message) {
hideLoading();
Toast.makeText(this, message, Toast.LENGTH_SHORT).show();
}
}
Presenter:同时持有View和Model,所有逻辑相关,不关心UI与数据。持有Model和View
package com.example.mvpdemo.presenter;
import com.example.mvpdemo.bean.UserBean;
/**
* 登录Presenter接口,处理交互
*/
public interface ILoginPresenter {
void login(String name,String password);
void loginSuccess(UserBean user);
void loginFail(String errMsg);
}
package com.example.mvpdemo.presenter;
import com.example.mvpdemo.bean.UserBean;
import com.example.mvpdemo.model.IUserBiz;
import com.example.mvpdemo.model.UserBiz;
import com.example.mvpdemo.view.ILoginView;
/**
* Presenter层,同时持有View和Model,只关心交互,不涉及双方逻辑
*/
public class LoginPresenter implements ILoginPresenter {
private IUserBiz mUserBiz;
private ILoginView mLoginView;
public LoginPresenter(ILoginView mLoginView) {
this.mLoginView = mLoginView;
this.mUserBiz = new UserBiz(this);
}
@Override
public void login(String name, String password) {
String result = mUserBiz.login(name, password);
if(result...){ // 成功逻辑
loginSuccess(user);
} else {
loginFail(errMsg);
}
}
@Override
public void loginSuccess(UserBean user) {
mLoginView.toSuccessPage(user);
}
@Override
public void loginFail(String errMsg) {
mLoginView.showErrMessage(errMsg);
}
}
如上。MVP之外的所有东西都不包含,实现简单的分层。
已修正:2018.12.24 错误的理解了P与M层。