mvc與mvp的比較.png
比較兩種架構的文章已經很多了,我不再贅述。
以一個簡單的登錄操作為例:
先說View
public interface BaseInterface {
/**
* 顯示請求中dialog
*/
public void showDownloadingDialog();
/**
* 隱藏請求中dialog
*/
public void dismissDownloadingDialog();
/**
* 網絡錯誤
*/
public void showInternetError();
}
上面定義了凡是具有網絡請求的界面都必備的方法。
下面是LoginActivity所特有的一些操作。
public interface ILoginView extends BaseInterface {
/**
* 登錄成功后干啥
*/
public void loginSuccess();
/**
* 登錄失敗后干啥
*/
public void loginFailed();
/**
* 返回賬號
*/
public String getAccount();
/**
* 返回密碼
*/
public String getPsw();
}
接下來是LoginActivity的具體實現。
public class LoginView extends BaseActivity implements ILoginView {
ILoginPresenter iLoginPresenter = null;
@Bind(R.id.etAccount)
EditText etAccount;
@Bind(R.id.etPsw)
EditText etPsw;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
subSetContentView(R.layout.activity_login);
iLoginPresenter = new LoginPresenter(this);
}
@Override
public void loginSuccess() {
Toast.makeText(this, "登錄成功", Toast.LENGTH_SHORT).show();
}
@Override
public String getAccount() {
return etAccount.getText().toString().trim();
}
@Override
public String getPsw() {
return etPsw.getText().toString().trim();
}
@Override
public void loginFailed() {
Toast.makeText(this, "賬號或密碼錯誤", Toast.LENGTH_SHORT).show();
}
@OnClick({R.id.btnLogin})
@Override
public void onClick(View v) {
super.onClick(v);
switch (v.getId()) {
case R.id.btnLogin:
iLoginPresenter.login();
break;
}
}
細心的你也許會想,BaseInterface接口里面的三個方法去哪實現了呢,答案在BaseActivity里。
public class BaseActivity extends Activity implements OnClickListener {
//略去其他代碼
public void showDownloadingDialog() {
Toast.makeText(this, "showDownloadingDialog ...", Toast.LENGTH_SHORT)
.show();
}
public void dismissDownloadingDialog() {
Toast.makeText(this, "dismissDownloadingDialog ...", Toast.LENGTH_SHORT)
.show();
}
public void showInternetError() {
Toast.makeText(this, "網絡錯誤", Toast.LENGTH_SHORT).show();
}
}
接下來說Presenter
public interface ILoginPresenter {
public void login();
}
public class LoginPresenter implements ILoginPresenter {
private ILoginView iLoginView = null;
private LoginModel loginModel = null;
public LoginPresenter(ILoginView iLoginView) {
this.iLoginView = iLoginView;
this.loginModel = new LoginModel();
}
@Override
public void login() {
String account = iLoginView.getAccount();
String psw = iLoginView.getPsw();
iLoginView.showDownloadingDialog();
// 1.模擬本地登錄
boolean ifSuccess = loginModel.loginLocal(account, psw);
if (ifSuccess) {
iLoginView.loginSuccess();
} else {
iLoginView.loginFailed();
}
// 2.模擬網絡登錄
loginModel.loginInternet(account, psw, new OnLoginListener() {
@Override
public void loginSuccess() {
iLoginView.dismissDownloadingDialog();
iLoginView.loginSuccess();
}
@Override
public void loginFailed() {
iLoginView.dismissDownloadingDialog();
iLoginView.loginFailed();
}
@Override
public void internetError() {
iLoginView.dismissDownloadingDialog();
iLoginView.showInternetError();
}
});
}
/**
* 用于獲取用戶登錄結果的回調
*/
public interface OnLoginListener {
void loginSuccess();
void loginFailed();
void internetError();
}
}
最后說Model
public class LoginModel {
/**
* 通過查詢本地數據庫驗證用戶名密碼是否正確,未開啟子線程
*/
public boolean loginLocal(String account, String psw) {
String temp = "1";
if (temp.equals(account) && temp.equals(psw)) {
return true;
} else {
return false;
}
}
/**
* 通過網絡,向服務器驗證用戶名密碼是否合法,需要傳入回調
*/
public void loginInternet(String account, String psw,
LoginPresenter.OnLoginListener onLoginListener) {
// do some internet thing
// if success,invoke onLoginListener.loginSuccess() and maybe need to store necessary data to local DB;
// if failed,invoke onLoginListener.loginFailed();
// if internet error,invoke onLoginListener.internetError();
}
}
好像忘記介紹activity布局了,很簡單
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:padding="10dp">
<EditText
android:id="@+id/etAccount"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="賬號" />
<EditText
android:id="@+id/etPsw"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="密碼" />
<Button
android:id="@+id/btnLogin"
style="@style/btn_universal"
android:text="登錄" />
</LinearLayout>
效果就是醬嬸兒的
沒什么好看的.png
一點體會
Activity代碼是不是清爽了很多,因為業務邏輯都被剝離出去了。
什么是接口?接口就是“協議”啊。業務邏輯通常是代表了一系列或繁或簡的操作,如果全部在View里面實現,會搞得代碼非常難以維護,這顯然是不合理的。所以,在MVP中,View只定義了這一系列操作的開端,例如,點擊了登錄按鈕,具體業務是在presenter中實現的。可以這樣做的前提是,View與Presenter之間已經簽訂了協議——“你需要我干什么,按照協議里商量的好的辦法告訴我就行了”。