簡介
- MVP 是從經(jīng)典的模式MVC演變而來。
- 在MVC/MVP模式中Controller/Presenter負責邏輯的處理,Model提供數(shù)據(jù),View負責顯示。
-
但是MVP與MVC有著一個重大的區(qū)別:在MVP中View并不直接使用Model,它們之間的通信是通過Presenter (MVC中的Controller)來進行的,所有的交互都發(fā)生在Presenter內(nèi)部,而在MVC中View會直接從Model中讀取數(shù)據(jù)而不是通過 Controller。
MVC模式中三者的關(guān)系:
MVC模式.png
MVP模式中三者的關(guān)系:
MVP模式.png - 事實上,android中的activity就是用到了MVC模式。其中的View對應(yīng)Activity中與XML文件對應(yīng)的View控件部分,而Model則對應(yīng)數(shù)據(jù)庫文件,Sharedprefrence,內(nèi)存緩沖,磁盤緩沖等數(shù)據(jù)內(nèi)容。至于Controller控制層基本上也由Activity層面來進行。
- 從上面可以看出,在android中,activity同時充當了V和C的角色,使得activity的代碼往往會過于臃腫,也不符合“單一職責”的原則,所以MVP模式就出現(xiàn)了。
- MVP模式出現(xiàn)后Activity就可以只充當V的角色,M對V或者V對M來說幾乎是完全透明的,提高了系統(tǒng)的可維護性和擴展性。
實例
- 接下來通過一個登陸界面來運用MVP模式。
- ILoginModel即Model的接口:
public interface ILoginModel {
boolean doLogin(String name,String passwrod);
}
其實就是實現(xiàn)一個向遠端服務(wù)器驗證的功能。
- LoginModel即ILoginModel的實現(xiàn)類:
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的方法則是點擊按鈕后需要調(diào)用的login方法。
- LoginPresenter即Presenter類,View和Model交接的中轉(zhuǎn)站,負責邏輯的處理。
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方法中首先調(diào)用View的showLoading()展示加載框,然后新開線程做耗時操作,并通過回調(diào)執(zhí)行對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其中一方的改變都不會影響其他的一方。
總結(jié)
- mvp模式比較適合大型的APP開發(fā),越復(fù)雜它的優(yōu)勢越明顯,但是如果頁面本身很簡單,使用MVP模式就會加大工作量,比如上面的登陸界面,明明一個Activity就可以搞定,卻被分成了多個接口和類。

