****前言****
以前在寫Web項(xiàng)目的時(shí)候,也許沒(méi)有過(guò)多的考慮項(xiàng)目的開發(fā)模式,然而習(xí)慣了采用MVC的模式去開發(fā)項(xiàng)目,然而最近開發(fā)Android項(xiàng)目的時(shí)候,總是感覺(jué)View和Model聯(lián)系很緊密,從邏輯上基本不能分離出來(lái),然后就了解到了MVP模式,這種模式View層與Model層完全分離的,從而減輕了Activity的負(fù)擔(dān)。
- MVP模式的簡(jiǎn)介
MVP開發(fā)模式是從經(jīng)典的MVC模式演變過(guò)來(lái)的,其基本思路都是相通的。簡(jiǎn)單來(lái)說(shuō):MVP模式是基于MVC模式的。
****M是Model層,提供業(yè)務(wù)數(shù)據(jù)****
****V是View視圖,顯示數(shù)據(jù)****
****P是Presenter控制者,進(jìn)行邏輯處理****
- MVP模式與MVC模式的區(qū)別

從圖中可以清晰地看出:它們有一個(gè)比較明顯的區(qū)別就是,MVC中是允許Model和View進(jìn)行交互的;而MVP中很明顯,Model與View之間的交互由Presenter完成,并且Presenter與View之間的交互是通過(guò)接口的,換句話說(shuō):在MVP中View并不直接使用Model,它們之間的通信是通過(guò)Presenter來(lái)進(jìn)行的,所有的交互都發(fā)生在Presenter內(nèi)部。
- MVP模式的優(yōu)缺點(diǎn)
優(yōu)點(diǎn):降低耦合,代碼靈,層級(jí)職責(zé)更明顯,易于單元測(cè)試
缺點(diǎn):造成類數(shù)量爆炸,代碼復(fù)雜度和學(xué)習(xí)成本高,在某些場(chǎng)景下presenter的復(fù)用會(huì)產(chǎn)生接口冗余
入門的體驗(yàn):給一個(gè)demo你看的話,你會(huì)發(fā)現(xiàn)MVP模式開發(fā)的思路很清晰,但是你會(huì)發(fā)覺(jué)項(xiàng)目會(huì)產(chǎn)生很多的類,代碼的復(fù)雜度會(huì)高些。網(wǎng)上常說(shuō):雖然mvp基于mvc,但是由于類太多未必可以寫的出來(lái)。
- MVP的小實(shí)戰(zhàn)DEMO
不想寫太多理論性的文筆,接下來(lái)講解demo的編程思路【代碼展示-用戶登陸】
****demo的項(xiàng)目結(jié)構(gòu)****

****Bean**** UserBean毋庸置疑這個(gè)必須有的,和mvc一樣
package com.samego.alic.demomvp.bean;
/**
* UserBean
* Created by alic on 16-4-13.
*/
public class User {
private String username;//用戶名
private String password;//密碼
//construct
public User() {
}
public User(String username, String password) {
this.username = username;
this.password = password;
}
//set and get start
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;
}
//set and get end
}
****Model**** 從業(yè)務(wù)上思考,User至少有l(wèi)ogin()該方法
package com.samego.alic.demomvp.model;
import com.samego.alic.demomvp.presenter.OnLoginListener;
/**
*UserModel接口
* Created by alic on 16-4-13.
*/
public interface UserModel {
/**
* 用戶登陸
* @param username 用戶名
* @param password 密碼
* @param onLoginListener 登陸結(jié)果監(jiān)聽(tīng)是否登陸成功
*/
void login(String username,String password,OnLoginListener onLoginListener);
}
package com.samego.alic.demomvp.model;
/**
*UserModelImpl類實(shí)現(xiàn)UserModel接口
* Created by alic on 16-4-13.
*/
public class UserModelImpl implements UserModel {
@Override
public void login(final String username, final String password, final OnLoginListener loginListener) {
new Thread(){
@Override
public void run() {
try {
//模擬網(wǎng)絡(luò)數(shù)據(jù)交互等待時(shí)間
Thread.sleep(2000);
//模擬登陸成功
if("alic".equals(username)&&"123456".equals(password)){
User user = new User(username,password);
loginListener.loginSuccess(user);
//模擬登陸失敗
}else {
loginListener.loginFailed();
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}.start();
}
}
package com.samego.alic.demomvp.model;
/**
*登陸監(jiān)聽(tīng)接口
* Created by alic on 16-4-13.
*/
public interface OnLoginListener {
/**
* 用戶登陸成功
* @param user UserBean
*/
void loginSuccess(User user);
/**
* 用戶登陸失敗
*/
void loginFailed();
}
****View**** 難點(diǎn)就是在View這里,View該有哪些方法,因?yàn)镻resenter與View交互是通過(guò)接口。
簡(jiǎn)單分析該接口應(yīng)該有哪些方法,****其實(shí)這些方法就是輔助Presenter的邏輯而存在的****
//獲取用戶名 密碼
String getUsername();
String getPassword();
//清空用戶名 密碼
void clearUsername();
void clearPassword();
//顯示 隱藏加載
void showLoading();
void hideLoading();
//跳轉(zhuǎn)主界面
void toMainActivity(User user);~~~
//顯示錯(cuò)誤
void showFailed();
Summary
package com.samego.alic.demomvp.view;
import com.samego.alic.demomvp.bean.User;
/**
*用戶登錄輔助視圖view 雖然由activity顯示,目的就是輔助Presenter
-
Created by alic on 16-4-13.
*/
public interface UserLoginView {
//獲取用戶名 密碼
String getUsername();
String getPassword();//清空用戶名 密碼
void clearUsername();
void clearPassword();//顯示 隱藏加載
void showLoading();
void hideLoading();//跳轉(zhuǎn)主界面
void toMainActivity(User user);//顯示錯(cuò)誤
void showFailed();
}
package com.samego.alic.demomvp.view;
/**
*用戶登陸界面主視圖view
*Created by alic on 16-4-13.
*/
public class LoginActivity extends AppCompatActivity implements UserLoginView, View.OnClickListener {
private EditText username,password;
private Button login,reset;
private ProgressBar loginLoading;
private UserLoginPresenter loginPresenter = new UserLoginPresenter(this);
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_login);
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
StatusBarCompat.setStatusBarColor(this,StatusBarCompat.COLOR_ToolBar_HIGHTBLUE);
//初始化
initViews();
}
/**
* 初始化視圖組件
*/
public void initViews(){
username = (EditText) findViewById(R.id.login_username);
password = (EditText) findViewById(R.id.login_password);
login = (Button) findViewById(R.id.login_button);
reset = (Button) findViewById(R.id.reset_button);
loginLoading = (ProgressBar) findViewById(R.id.login_loading);
loginLoading.setVisibility(View.INVISIBLE);
login.setOnClickListener(this);
reset.setOnClickListener(this);
}
@Override
public String getUsername() {
return username.getText().toString();
}
@Override
public String getPassword() {
return password.getText().toString();
}
@Override
public void clearUsername() {
username.setText("");
}
@Override
public void clearPassword() {
password.setText("");
}
@Override
public void showLoading() {
loginLoading.setVisibility(View.VISIBLE);
}
@Override
public void hideLoading() {
loginLoading.setVisibility(View.INVISIBLE);
}
@Override
public void toMainActivity(User user) {
// Intent intent = new Intent(LoginActivity.this,MainActivity.class);
// startActivity(intent);
Toast.makeText(this,"登陸成功",Toast.LENGTH_SHORT).show();
}
@Override
public void showFailed() {
Toast.makeText(this,"用戶名或密碼錯(cuò)誤",Toast.LENGTH_SHORT).show();
}
@Override
public void onClick(View v) {
switch (v.getId()){
case R.id.login_button:
loginPresenter.login();
break;
case R.id.reset_button:
loginPresenter.clear();
break;
default:
break;
}
}
}
****Presenter**** Presenter是用作Model和View之間交互的橋梁,該方法也應(yīng)該有哪些方法呢,****這些方法其實(shí)就是我們?cè)诮缑嫔纤吹降倪壿嬏幚?***,比如login()以及reset()
package com.samego.alic.demomvp.presenter;
/**
*UserLoginPresenter
Presenter負(fù)責(zé)完成UserLoginView層與UserModel層的交互
-
Created by alic on 16-4-13.
*/
public class UserLoginPresenter {
private UserModel userModel;
private UserLoginView userLoginView;
private Handler handler = new Handler();//construct
public UserLoginPresenter(UserLoginView userLoginView) {
this.userLoginView = userLoginView;
userModel = new UserModelImpl();
}/**
-
登陸function
*/
public void login(){
userLoginView.showLoading();
userModel.login(userLoginView.getUsername(), userLoginView.getPassword(), new OnLoginListener() {
@Override
public void loginSuccess(final User user) {
handler.post(new Runnable() {
@Override
public void run() {
userLoginView.toMainActivity(user);
userLoginView.hideLoading();
}
});
}@Override public void loginFailed() { handler.post(new Runnable() { @Override public void run() { userLoginView.showFailed(); userLoginView.hideLoading(); } }); }});
}
/**
- 清空f(shuō)unction
*/
public void clear(){
userLoginView.clearUsername();
userLoginView.clearPassword();
}
}
-
以上就是一個(gè)非常精簡(jiǎn)又經(jīng)典的Demo,對(duì)于有些不了解的或者不對(duì)的地方歡迎交談,THX!