MVP是MVC的衍生版本,跟MVC相似,可是在Android中更適用,也分三層: java
Model:用於數據的增刪改查等,也包括一些數據對象 android
View:用於界面的顯示與用戶操做的接收,在Android裏面View一般就是Actvitiy,Fragment。 服務器
Presenter:是View跟Model的「中間人」,接收View的請求後,從Model獲取數據交給View。app
MVP&MVC的區別ide
傳統MVC有着悠久的歷史,可是Android卻選用MVP,這絕非偶然。 post
在MVC中: this
M:解決用什麼去渲染 spa
V:解決怎麼去渲染 線程
C:解決用戶輸入事件code
在Android中,假如使用MVC,表明V的layout資源並不能徹底解決怎麼去渲染的問題,還須要Activity的輔助,因此Activity也必然要表明V;可是同時,Activity一方面擁有生命週期回調,另一方面還爲View設置監聽,Activity接收來自用戶的輸入,因此Activity也必然也表明C,Activity就像一個萬能對象同時表明着V與C。所以,使用MVC並不能很好地將V與C分離開來。
與MVC不一樣的是,MVP中的View是能夠接收用戶輸入,同時也能解決怎麼去渲染的問題,因此Activity能夠做爲MVP裏面的View,可是卻作不了MVC裏面的View。所以,MVP更適用於Android。
可是View的改變不僅在此:View在一方面增長了接收事件的責任,又在另外一方面減小了操做Model的責任。View再也不直接操做Model,只能經過Presenter去Model操做數據。能夠說,MVC中的View與Control交換了部分工做,就成了如今的MVP。
簡單例子:
效果圖:
項目結構圖:
(一)Model
首先實體類User不用考慮這個確定有,其次從效果圖能夠看到至少有一個業務方法login(),這兩點沒什麼難度,咱們首先完成:
package com.zhy.blogcodes.mvp.bean; public class User{ private String username ; private String password ; public String getUsername() { return username; } public void setUsername(String username) { this.username = username; } public String getPassword() { return password; } public void setPassword(String password) { this.password = password; } }
package com.zhy.blogcodes.mvp.biz; public interface IUserBiz{ public void login(String username, String password, OnLoginListener loginListener); }
package com.zhy.blogcodes.mvp.biz; import com.zhy.blogcodes.mvp.bean.User; public class UserBiz implements IUserBiz { @Override public void login(final String username, final String password, final OnLoginListener loginL istener) { // 模擬子線程耗時操做 new Thread() { @Override public void run() { try { Thread.sleep(2000); } catch (InterruptedException e) { e.printStackTrace(); } // 模擬登陸成功 if ("zhy".equals(username) && "123".equals(password)) { User user = new User(); user.setUsername(username); user.setPassword(password); loginListener.loginSuccess(user); } else { loginListener.loginFailed(); } } }.start(); } }
package com.zhy.blogcodes.mvp.biz; import com.zhy.blogcodes.mvp.bean.User; public interface OnLoginListener{ void loginSuccess(User user); void loginFailed(); }
實體類不用說,至於業務類,咱們抽取了一個接口,一個實現類這也很常見~~login方法,通常確定是鏈接服務器的,是個耗時操做,因此咱們開闢了子線程,Thread.sleep(2000)模擬了耗時,因爲是耗時操做,因此咱們經過一個回調接口來通知登陸的狀態。
其實這裏仍是比較好寫的,由於和傳統寫法沒區別。
(二) View
上面咱們說過,Presenter與View交互是經過接口。因此咱們這裏須要定義一個ILoginView,難點就在於應該有哪些方法,咱們看一眼效果圖:
能夠看到咱們有兩個按鈕,一個是login,一個是clear;
login說明了要有用戶名、密碼,那麼對應兩個方法:
String getUserName(); String getPassword();
再者login是個耗時操做,咱們須要給用戶一個友好的提示,通常就是操做ProgressBar,因此再兩個:
void showLoading(); void hideLoading();
login固然存在登陸成功與失敗的處理,咱們主要當作功咱們是跳轉Activity,而失敗多是去給個提醒:
void toMainActivity(User user); void showFailedError();
ok,login這個方法咱們分析完了~~還剩個clear那就簡單了:
void clearUserName(); void clearPassword();
綜上,接口完整爲:
package com.zhy.blogcodes.mvp.view; import com.zhy.blogcodes.mvp.bean.User; public interface IUserLoginView { String getUserName(); String getPassword(); void clearUserName(); void clearPassword(); void showLoading(); void hideLoading(); void toMainActivity(User user); void showFailedError(); }
有了接口,實現就太好寫了~~~
總結下,對於View的接口,去觀察功能上的操做,而後考慮:
該操做須要什麼?(getUserName, getPassword)
該操做的結果,對應的反饋?(toMainActivity, showFailedError)
該操做過程當中對應的友好的交互?(showLoading, hideLoading)
下面貼一下咱們的View的實現類,哈,其實就是Activity,文章開始就說過,MVP中的View其實就是Activity。
package com.zhy.blogcodes.mvp; import android.os.Bundle; import android.support.v7.app.ActionBarActivity; import android.view.View; import android.widget.Button; import android.widget.EditText; import android.widget.ProgressBar; import android.widget.Toast; import com.zhy.blogcodes.R; import com.zhy.blogcodes.mvp.bean.User; import com.zhy.blogcodes.mvp.presenter.UserLoginPresenter; import com.zhy.blogcodes.mvp.view.IUserLoginView; public class UserLoginActivity extends ActionBarActivity implements IUserLoginView { private EditText mEtUsername, mEtPassword; private Button mBtnLogin, mBtnClear; private ProgressBar mPbLoading; private UserLoginPresenter mUserLoginPresenter = new UserLoginPresenter(this); @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_user_login); initViews(); } private void initViews() { mEtUsername = (EditText) findViewById(R.id.id_et_username); mEtPassword = (EditText) findViewById(R.id.id_et_password); mBtnClear = (Button) findViewById(R.id.id_btn_clear); mBtnLogin = (Button) findViewById(R.id.id_btn_login); mPbLoading = (ProgressBar) findViewById(R.id.id_pb_loading); mBtnLogin.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { mUserLoginPresenter.login(); } }); mBtnClear.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { mUserLoginPresenter.clear(); } }); } @Override public String getUserName() { return mEtUsername.getText().toString(); } @Override public String getPassword() { return mEtPassword.getText().toString(); } @Override public void clearUserName() { mEtUsername.setText(""); } @Override public void clearPassword() { mEtPassword.setText(""); } @Override public void showLoading() { mPbLoading.setVisibility(View.VISIBLE); } @Override public void hideLoading() { mPbLoading.setVisibility(View.GONE); } @Override public void toMainActivity(User user) { Toast.makeText(this, user.getUsername() + " login success , to MainActivity", Toast.LENGTH_SHORT).show(); } @Override public void showFailedError() { Toast.makeText(this, "login failed", Toast.LENGTH_SHORT).show(); } }
對於在Activity中實現咱們上述定義的接口,是一件很容易的事,畢竟接口引導咱們去完成。
最後看咱們的Presenter。
(三)Presenter
Presenter是用做Model和View之間交互的橋樑,那麼應該有什麼方法呢?
其實也是主要看該功能有什麼操做,好比本例,兩個操做:login和clear。
package com.zhy.blogcodes.mvp.presenter; import android.os.Handler; import com.zhy.blogcodes.mvp.bean.User; import com.zhy.blogcodes.mvp.biz.IUserBiz; import com.zhy.blogcodes.mvp.biz.OnLoginListener; import com.zhy.blogcodes.mvp.biz.UserBiz; import com.zhy.blogcodes.mvp.view.IUserLoginView; public class UserLoginPresenter { private IUserBiz userBiz; private IUserLoginView userLoginView; private Handler mHandler = new Handler(); public UserLoginPresenter(IUserLoginView userLoginView) { this.userLoginView = userLoginView; this.userBiz = new UserBiz(); } public void login() { userLoginView.showLoading(); userBiz.login(userLoginView.getUserName(), userLoginView.getPassword(), new OnLoginListener() { @Override public void loginSuccess(final User user) { // 須要在UI線程執行 mHandler.post(new Runnable() { @Override public void run() { userLoginView.toMainActivity(user); userLoginView.hideLoading(); } }); } @Override public void loginFailed() { // 須要在UI線程執行 mHandler.post(new Runnable() { @Override public void run() { userLoginView.showFailedError(); userLoginView.hideLoading(); } }); } }); } public void clear() { userLoginView.clearUserName(); userLoginView.clearPassword(); } }
注意上述代碼,咱們的presenter完成兩者的交互,那麼確定須要兩者的實現類。大體就是從View中獲取須要的參數,交給Model去執行業務方法,執行的過程當中須要的反饋,以及結果,再讓View進行作對應的顯示。