一、初識MVP(Model View Presenter)
google上關於MVP模式的資料已經特別多了,所以我這裡也不囉嗦了。 因為之前做過的幾個專案,每個Activity的所有操作程式碼全部都是堆在裡面,雖然查詢還算方便,但是程式碼動不動就上千行,所以維護起來特別麻煩,如果程式碼沒有註釋,那對於我們來說簡直就是災難! 所以這次決定把MVP模式放在真實專案中玩玩,以下也是我從真實專案中使用的一些小感受。
二、專案例項----【登入+註冊+獲取驗證碼+重置密碼】
2.1 MVP中的Model 首先我們得建立一個存放Model的包,我這裡命名為Biz。 AccountListener類中存放的都是相關操作的介面,每個介面中都有操作成功和操作失敗的方法回撥,至於裡面的引數都可根據實際情況進行定義。
/**
* author:silencezwm on 16/6/1 10:24
* email:silencezwm@gmail.com
* description:賬號監聽
*/
public class AccountListener {
/**
* 登入監聽介面
*/
public interface LoginListener {
void loginSuccess();
void loginFailed(String msg);
}
/**
* 註冊賬號監聽介面
*/
public interface RegListener {
void regSuccess();
void regFailed(String msg);
}
/**
* 獲取驗證碼監聽介面
*/
public interface GetVerCodeListener {
void getVerCodeSuccess();
void getVerCodeFailed(String msg);
}
/**
* 獲取忘記密碼驗證碼監聽介面
*/
public interface GetForgetPwdVerCodeListener {
void getForgetPwdVerCodeSuccess();
void getForgetPwdVerCodeFailed(String msg);
}
/**
* 核驗驗證碼是否正確
*/
public interface CheckVerCodeListener{
void checkVerCodeSuccess();
void checkVerCodeFailed(String msg);
}
/**
* 重置密碼監聽介面
*/
public interface ResetPwdListener {
void resetPwdSuccess();
void resetPwdFailed(String msg);
}
}
複製程式碼
在IAccountBiz介面中定義的都是請求網路需要的引數,同樣也放在Model下。
/**
* author:silencezwm on 16/6/1 11:33
* email:silencezwm@gmail.com
* description:賬戶相關操作所有介面Biz
*/
public interface IAccountBiz {
/**
*
* @param userName 使用者名稱
* @param pwd 密碼
* @param loginListener 使用者登入監聽
*/
void login(String userName, String pwd, LoginListener loginListener);
/**
*
* @param mobile 手機號
* @param password 密碼
* @param validateCode 驗證碼
* @param regListener 使用者註冊監聽
*/
void register(String mobile, String password, String validateCode, RegListener regListener);
/**
*
* @param mobile 手機號
* @param getVerCodeListener 獲取驗證碼監聽
*/
void getVerifyCode(String mobile, GetVerCodeListener getVerCodeListener);
/**
*
* @param mobile 手機號
* @param getForgetPwdVerCodeListener 獲取忘記密碼驗證碼監聽
*/
void getForgetPwdVerifyCode(String mobile,GetForgetPwdVerCodeListener getForgetPwdVerCodeListener);
/**
*
* @param mobile 手機號
* @param verCode 驗證碼
* @param checkVerCodeListener 核驗驗證碼是否正確監聽
*/
void checkVerCode(String mobile, String verCode, AccountListener.CheckVerCodeListener checkVerCodeListener);
/**
*
* @param mobile 手機號
* @param newPwd 新密碼
* @param resetPwdListener 重置密碼監聽
*/
void resetPwd(String mobile, String newPwd, ResetPwdListener resetPwdListener);
}
複製程式碼
Model下的AccountBiz類實現IAccountBiz介面,並顯示其所有方法,這裡就會進行網路請求,這裡我會隱藏部分網路請求程式碼。
/**
* author:silencezwm on 16/6/1 12:00
* email:silencezwm@gmail.com
* description:登入邏輯處理
*/
public class AccountBiz implements IAccountBiz {
/**
*
* @param userName 使用者名稱
* @param pwd 密碼
* @param loginListener 使用者登入監聽
*/
@Override
public void login(String userName, String pwd, final LoginListener loginListener) {
*******這裡編寫網路請求程式碼*******
-------請求成功後,呼叫loginListener.loginSuccess();
-------請求失敗後,呼叫
loginListener.loginFailed(msg);
*******其他幾個請求方法同上,此處省略*******
}
複製程式碼
**到這裡Model層的工作基本完成了,接下來我們瞧瞧View層。
2.2 MVP中的View View層完全不用去管Model層做了啥,怎麼做的問題,它只需要把Activity伺候好就行。 AccountView類中放在View包下,所有在Model中需要Activity提供的資料或者Model層和伺服器互動後返回的資料也由View傳給Activity的。
/**
* author:silencezwm on 16/6/1 12:25
* email:silencezwm@gmail.com
* description:登入相關
*/
public class AccountView {
/**
* 登入介面
*/
public interface ILoginView {
/**
* @return 獲取使用者名稱
*/
String getUserName();
/**
* @return 獲取密碼
*/
String getPwd();
/**
* 登入成功後返回資訊
*/
void loginSuccess();
/**
* 登入失敗
*/
void loginFailed(String msg);
}
/**
* 獲取驗證碼介面
*/
public interface IGetVerCodeView {
/**
* @return 獲取手機號
*/
String getMobile();
/**
* 獲取驗證碼成功
*/
void getVerCodeSuccess();
/**
* 獲取驗證碼失敗
*/
void getVerCodeFailed(String msg);
}
/**
* 獲取忘記密碼驗證碼介面
*/
public interface IGetForgetPwdVerCodeView {
/**
* @return 獲取手機號
*/
String getMobile();
/**
* 獲取忘記密碼驗證碼成功
*/
void getForgetPwdVerCodeSuccess();
/**
* 獲取忘記密碼驗證碼失敗
*/
void getForgetPwdVerCodeFailed(String msg);
}
/**
* 核驗驗證碼是否正確介面
*/
public interface ICheckVerCodeView {
/**
* @return 獲取手機號
*/
String getCheckVerCodeMobile();
/**
*
* @return 驗證碼
*/
String getCheckVerCode();
/**
* 核驗驗證碼成功
*/
void checkVerCodeSuccess();
/**
* 核驗驗證碼失敗
*/
void checkVerCodeFailed(String msg);
}
/**
* 註冊介面
*/
public interface IRegView {
/**
* @return 獲取手機號
*/
String getRegMobile();
/**
* @return 獲取驗證碼
*/
String getRegVerCode();
/**
* @return 獲取密碼
*/
String getRegPwd();
/**
* 註冊成功
*/
void regSuccess();
/**
* 註冊失敗
*/
void regFailed(String msg);
}
/**
* 重置密碼
*/
public interface IResetPwdView {
/**
* @return 新密碼
*/
String getNewPwd();
/**
* @return 手機號
*/
String getMobile();
/**
* 重置密碼成功
*/
void resetPwdSuccess();
/**
* 重置密碼失敗
*/
void resetPwdFailed(String msg);
}
}
複製程式碼
到這裡View層的工作也完成了,其實難度並不大,後續相關Activity只需實現View中的相關介面,並顯示其中所有的方法即可
2.3 MVP中的的主角Presenter 先打個比方,牛郎和織女不是每年得相會嘛,他們中間得有座橋才行。在MVP中Model和View就像牛郎織女,而橋就是Presenter,所以正是Presenter把Model和View聯絡在一起的,這樣也使得程式碼得到了解耦,各層各司其職。
/**
* author:silencezwm on 16/6/1 12:55
* email:silencezwm@gmail.com
* description:登入Presenter
*/
public class LoginPresenter {
private IAccountBiz mILoginBiz;
private ILoginView mILoginView;
//在相關Activity中例項化此Presenter,並傳入相關View
public LoginPresenter(ILoginView ILoginView) {
mILoginView = ILoginView;
mILoginBiz = new AccountBiz();
}
public void login(){mILoginBiz.login(mILoginView.getUserName(), mILoginView.getPwd(), new LoginListener() {
@Override
public void loginSuccess() {
//登入成功後,呼叫View的回撥方法,將成功資訊返回給Activity
mILoginView.loginSuccess();
}
@Override
public void loginFailed(String msg) {
//登入失敗後,呼叫View的回撥方法,將錯誤資訊返回給Activity
mILoginView.loginFailed(msg);
}
});
}
}
複製程式碼
此時這根橋就搭建完畢了,搞了這麼久,現在我們終於可以在相關Activity中進行使用了
2.4 在相關Activity中使用 1、實現相應View介面,並實現其所有方法 2、例項化Presenter,並去呼叫相關方法 接下來看具體程式碼實現:
/**
* author:silencezwm on 16/6/1 13:16
* email:silencezwm@gmail.com
* description:登入Fragment
*/
public class LoginFragment extends BaseFragment implements ILoginView {
@Bind(R.id.et_input_username)
EditText et_input_username;
@Bind(R.id.et_input_pwd)
EditText et_input_pwd;
private View loginView;
//例項化登入相關Presenter
private LoginPresenter mLoginPresenter = new LoginPresenter(this);
@Nullable
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
loginView = inflater.inflate(R.layout.fragment_login, container, false);
ButterKnife.bind(this, loginView);
return loginView;
}
@OnClick({R.id.btn_login, R.id.text_forget_pwd})
public void clickOpreation(View v) {
switch (v.getId()) {
//登入
case R.id.btn_login:
if (et_input_username.getText().toString().isEmpty()){
ToastUtil.showToast(getActivity(), "手機號不能為空");
return;
}
if (et_input_pwd.getText().toString().isEmpty()){
ToastUtil.showToast(getActivity(), "密碼不能為空");
return;
}
if(!RegexUtils.checkMobile(et_input_username.getText().toString())){
ToastUtil.showToast(getActivity(), "請輸入合法的手機號");
return;
}
//登入
mLoginPresenter.login();
break;
//忘記密碼
case R.id.text_forget_pwd:
openActivity(ForgetPwdActivity.class);
break;
}
}
/**
* 獲取輸入使用者名稱
*
* @return
*/
@Override
public String getUserName() {
return et_input_username.getText().toString();
}
/**
* 獲取輸入密碼
*
* @return
*/
@Override
public String getPwd() {
return et_input_pwd.getText().toString();
}
/**
* 登入成功
*/
@Override
public void loginSuccess() {
ToastUtil.showToast(getActivity(), "登入成功");
}
/**
*
* @param msg 登入失敗資訊
*/
@Override
public void loginFailed(String msg) {
ToastUtil.showToast(getActivity(), msg);
}
@Override
public void onDestroy() {
super.onDestroy();
ButterKnife.unbind(this);
}
}
複製程式碼
三、MVP小總結 專案中使用了MVP的感受就是:
1、使用MVP後,程式碼量稍微多了點
2、把現在Activity和之前Activity相比較,使用MVP後,Activity中的程式碼量大幅度下降,程式碼閱讀、維護更方便。
複製程式碼
另外google官方也放出了一個MVP模式的專案android-architecture,旨在引導我等開發者,並非強制我們必須按照他的模式來哦,有興趣的可以去研究研究。