Android進階-MVP

1、什麼是MVP?android

MVP (Model View Presenter)模式由MVC模式演變而來,它將View層和邏輯層分離。git

2、爲何使用MVP?github

將View層和邏輯層分離後有利於拓展,好比當前代碼屬於來自本地數據庫,若是需求變動數據來自網絡,咱們就沒必要重寫整個View層。經過MVP咱們將大部分邏輯抽出Activity,寫在Presenter層。分層後就能夠各司其職,也方便測試。數據庫

3、各層的職責。編程

  1. Presenter的職責:從Modle層獲取數據通過處理後交給View層展現。
  2. View的職責:MVP將Activity劃在View層,Activity引用Presenter。View層主要有兩個任務。1.對外提供修改控件屬性的接口。2.響應外部事件,交給Presenter處理。這樣Activity的任務就很明確了。
  3. Model的職責:提供給Presenter須要的數據。

4、實例.網絡

一個登錄的例子(項目代碼在這裏下載:https://github.com/gatsbydhn/androidmvp):ide

View層:post

View接口,Activity實現了該接口,方便之後拓展:測試

 1 public interface LoginView {
 2     void showProgress();
 3 
 4     void hideProgress();
 5 
 6     void setUsernameError();
 7 
 8     void setPasswordError();
 9 
10     void navigateToHome();
11 }

Activity:this

 1 public class LoginActivity extends Activity implements LoginView, View.OnClickListener {
 2 
 3     private ProgressBar progressBar;
 4     private EditText username;
 5     private EditText password;
 6     private LoginPresenter presenter;
 7 
 8     @Override
 9     protected void onCreate(Bundle savedInstanceState) {
10         super.onCreate(savedInstanceState);
11         setContentView(R.layout.activity_login);
12 
13         progressBar = (ProgressBar) findViewById(R.id.progress);
14         username = (EditText) findViewById(R.id.username);
15         password = (EditText) findViewById(R.id.password);
16         findViewById(R.id.button).setOnClickListener(this);
17 
18         presenter = new LoginPresenterImpl(this);
19     }
20 
21     @Override protected void onDestroy() {
22         presenter.onDestroy();
23         super.onDestroy();
24     }
25 
26     @Override public void showProgress() {
27         progressBar.setVisibility(View.VISIBLE);
28     }
29 
30     @Override public void hideProgress() {
31         progressBar.setVisibility(View.GONE);
32     }
33 
34     @Override public void setUsernameError() {
35         username.setError(getString(R.string.username_error));
36     }
37 
38     @Override public void setPasswordError() {
39         password.setError(getString(R.string.password_error));
40     }
41 
42     @Override public void navigateToHome() {
43         startActivity(new Intent(this, MainActivity.class));
44         finish();
45     }
46 
47     @Override public void onClick(View v) {
48         presenter.validateCredentials(username.getText().toString(), password.getText().toString());
49     }
50 }

分析:如前面所說Activilty裏面的方法分爲兩類:1.修改控件屬性如showProgress(),hideProgress()等,這些接口將被Presenter調用。2.響應外部事件好比onClick(),onDestroy()等,調用Presenter來完成具體的任務。

下面是Presenter層:

接口,方便拓展:

1 public interface LoginPresenter {
2     void validateCredentials(String username, String password);
3 
4     void onDestroy();
5 }

實現類:

 1 public class LoginPresenterImpl implements LoginPresenter, LoginInteractor.OnLoginFinishedListener {
 2 
 3     private LoginView loginView;
 4     private LoginInteractor loginInteractor;
 5 
 6     public LoginPresenterImpl(LoginView loginView) {
 7         this.loginView = loginView;
 8         this.loginInteractor = new LoginInteractorImpl();
 9     }
10 
11     @Override public void validateCredentials(String username, String password) {
12         if (loginView != null) {
13             loginView.showProgress();
14         }
15 
16         loginInteractor.login(username, password, this);
17     }
18 
19     @Override public void onDestroy() {
20         loginView = null;
21     }
22 
23     @Override public void onUsernameError() {
24         if (loginView != null) {
25             loginView.setUsernameError();
26             loginView.hideProgress();
27         }
28     }
29 
30     @Override public void onPasswordError() {
31         if (loginView != null) {
32             loginView.setPasswordError();
33             loginView.hideProgress();
34         }
35     }
36 
37     @Override public void onSuccess() {
38         if (loginView != null) {
39             loginView.navigateToHome();
40         }
41     }
42 }

分析:這裏使用面向接口編程,方便之後拓展。Presenter引用Model層的LoginInteractor,完成View交給的任務validateCredentials(),該方法中調用LoginInteractor獲取登錄數據。

Model層:

接口:

 1 public interface LoginInteractor {
 2 
 3     interface OnLoginFinishedListener {
 4         void onUsernameError();
 5 
 6         void onPasswordError();
 7 
 8         void onSuccess();
 9     }
10 
11     void login(String username, String password, OnLoginFinishedListener listener);
12 
13 }

實現類:

 1 public class LoginInteractorImpl implements LoginInteractor {
 2 
 3     @Override
 4     public void login(final String username, final String password, final OnLoginFinishedListener listener) {
 5         // Mock login. I'm creating a handler to delay the answer a couple of seconds
 6         new Handler().postDelayed(new Runnable() {
 7             @Override public void run() {
 8                 boolean error = false;
 9                 if (TextUtils.isEmpty(username)){
10                     listener.onUsernameError();
11                     error = true;
12                 }
13                 if (TextUtils.isEmpty(password)){
14                     listener.onPasswordError();
15                     error = true;
16                 }
17                 if (!error){
18                     listener.onSuccess();
19                 }
20             }
21         }, 2000);
22     }
23 }

分析:登錄應該要從數據庫獲取數據驗證帳號密碼是否正確,這裏省略了這一步驟,可是要明白,這一層的職責是提供數據,無論是從數據庫仍是網絡。

相關文章
相關標籤/搜索