简介
- MVP 是从经典的模式MVC演变而来。
- 在MVC/MVP模式中Controller/Presenter负责逻辑的处理,Model提供数据,View负责显示。
-
但是MVP与MVC有着一个重大的区别:在MVP中View并不直接使用Model,它们之间的通信是通过Presenter (MVC中的Controller)来进行的,所有的交互都发生在Presenter内部,而在MVC中View会直接从Model中读取数据而不是通过 Controller。
MVC模式中三者的关系:
MVC模式.png
MVP模式中三者的关系:
MVP模式.png
- 事实上,android中的activity就是用到了MVC模式。其中的View对应Activity中与XML文件对应的View控件部分,而Model则对应数据库文件,Sharedprefrence,内存缓冲,磁盘缓冲等数据内容。至于Controller控制层基本上也由Activity层面来进行。
- 从上面可以看出,在android中,activity同时充当了V和C的角色,使得activity的代码往往会过于臃肿,也不符合“单一职责”的原则,所以MVP模式就出现了。
- MVP模式出现后Activity就可以只充当V的角色,M对V或者V对M来说几乎是完全透明的,提高了系统的可维护性和扩展性。
实例
- 接下来通过一个登陆界面来运用MVP模式。
- ILoginModel即Model的接口:
public interface ILoginModel {
boolean doLogin(String name,String passwrod);
}
其实就是实现一个向远端服务器验证的功能。
- LoginModel即ILoginModel的实现类:
public class LoginModel implements ILoginModel{
@Override
public boolean doLogin(final String name, final String passwrod) {
boolean result = false;
try {
Thread.sleep(3000);
result = name.equals(passwrod);
} catch (InterruptedException e) {
e.printStackTrace();
}
return result;
}
}
线程睡眠3秒,模拟后台验证的过程。
- LoginContract封装了View和Presenter的接口:
public interface LoginContract {
interface LoginView {
void setPresenter();
void showLoading();
void hideLoading();
void onSuccess();
void onFail();
}
interface LoginPresenter{
void login(String account, String password);
}
}
即View需要用的功能是展示加载条,取消加载条,登陆成功的页面显示,登陆失败的页面显示。而Presenter暴露给View的方法则是点击按钮后需要调用的login方法。
- LoginPresenter即Presenter类,View和Model交接的中转站,负责逻辑的处理。
public class LoginPresenter implements LoginContract.LoginPresenter {
LoginContract.LoginView mView;
ILoginModel mModel;
public LoginPresenter(LoginContract.LoginView mView) {
this.mView = mView;
this.mModel = new LoginModel();
}
@Override
public void login(final String account, final String password) {
mView.showLoading();
new Thread(new Runnable() {
@Override
public void run() {
final boolean result = mModel.doLogin(account,password);
Handler handler = new Handler(Looper.getMainLooper());
handler.post(new Runnable() {
@Override
public void run() {
if (result) {
mView.hideLoading();
mView.onSuccess();
}else {
mView.hideLoading();
mView.onFail();
}
}
});
}
}).start();
}
}
login方法中首先调用View的showLoading()展示加载框,然后新开线程做耗时操作,并通过回调执行对View的其他控制。
- LoginActivity即View层,负责界面的展示。
public class LoginActivity extends AppCompatActivity implements LoginContract.LoginView{
private Button mBtLogin;
private EditText mEtName;
private EditText mEtPassword;
private View mLoading;
LoginContract.LoginPresenter mPresenter;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_login);
initView();
setPresenter();
}
private void initView() {
mEtName = (EditText) findViewById(R.id.et_name);
mEtPassword = (EditText) findViewById(R.id.et_password);
mBtLogin = (Button) findViewById(R.id.bt_login);
mLoading = findViewById(R.id.layout_loading);
mBtLogin.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
String name = mEtName.getText().toString();
String password = mEtPassword.getText().toString();
mPresenter.login(name,password);
}
});
}
@Override
public void setPresenter() {
mPresenter = new LoginPresenter(this);
}
@Override
public void showLoading() {
mLoading.setVisibility(View.VISIBLE);
}
@Override
public void hideLoading() {
mLoading.setVisibility(View.GONE);
}
@Override
public void onSuccess() {
Toast.makeText(this,"登陆成功",Toast.LENGTH_SHORT).show();
}
@Override
public void onFail() {
Toast.makeText(this,"登陆失败",Toast.LENGTH_SHORT).show();
}
}
Presenter可通过契约类LoginContract 中View接口定义的方法来对View进行操作。
- 使用MVP模式后,M和V对互相透明,M和V其中一方的改变都不会影响其他的一方。
总结
- mvp模式比较适合大型的APP开发,越复杂它的优势越明显,但是如果页面本身很简单,使用MVP模式就会加大工作量,比如上面的登陆界面,明明一个Activity就可以搞定,却被分成了多个接口和类。
网友评论