Android中MVP的初步認(rèn)識與簡單用法

概述

認(rèn)識MVP模式

MVP 模式實(shí)際上指的是 Model-View-Presenter 主要的目的是為了劃分各個模塊的負(fù)責(zé)區(qū)域,分工明確趾唱,使代碼清晰了很多奴璃。也是為了減少 Activity 中代碼瞒滴,使其沒有那么臃腫,提高測試性哮缺,主要的分工如下:

View 主要是負(fù)責(zé)顯示數(shù)據(jù)和與用戶進(jìn)行交互弄跌,這可以是一個 Activity 或者是一個 Fragment,一個 android.view.View 或者是一個 Dialog尝苇。

Model 是數(shù)據(jù)源層铛只,負(fù)責(zé)對數(shù)據(jù)進(jìn)行存儲,檢索之類的操作糠溜。

Present 是 View 和 Model 進(jìn)行交互的中間橋梁淳玩,負(fù)責(zé) Model 和 View 兩者之間的處理,也就是說從Model中獲取的數(shù)據(jù)然后傳遞給 View非竿,起到一個中間人的作用蜕着,也是在 MVP 模式中處理復(fù)雜邏輯的地方,后臺任務(wù)也是它負(fù)責(zé)的汽馋。

為什么要使用 MVP 模式?

使其盡可能的簡單

  • 把復(fù)雜的任務(wù)分解成許多個簡單小任務(wù)來執(zhí)行
  • 分解成的小任務(wù) bug 比較少
  • 減少測試時間

后臺任務(wù)不和 Activity 關(guān)聯(lián)

當(dāng)你需要寫一個 Activity圈盔,F(xiàn)ragment 或者一個自定義 View 的時候豹芯,你可以將所有和后臺相關(guān)的方法放在一個外部類或者靜態(tài)類中,這樣你的后臺任務(wù)就不會和Activity有關(guān)聯(lián)驱敲,也不存在內(nèi)存的泄漏的問題铁蹈。

MVP 模式說明

其實(shí)在 MVP 中 Activity 對應(yīng)的就是 View,把 Activity 中的 UI 邏輯抽象成 View 接口众眨,在 View 中進(jìn)行 UI 設(shè)計(jì)和簡單的邏輯處理握牧,Model 是業(yè)務(wù)邏輯和實(shí)體模型的實(shí)現(xiàn),Presenter 負(fù)責(zé)完成View于Model間的交互(在這里進(jìn)行復(fù)雜的邏輯處理)娩梨,圖片來自這里

使用 MVP 模式

由上圖可以看出沿腰,在 MVP 模式中 Model 和 View 是不能直接交互的,而是通過 Presenter這個中間橋梁進(jìn)行交互狈定, MVP 和 MVC 模式最大的區(qū)別就在于此颂龙。也可以看出View和Presenter是一對一的關(guān)系,Model 可以為不同的 Presenter 提供數(shù)據(jù)服務(wù)纽什。一般來說 Presenter 與 View 的交互是通過接口來進(jìn)行的措嵌,這樣有利于添加單元測試。

MVP 實(shí)例講解

說了那么多還是用一個 Demo 來說一下芦缰,這樣就比較好理解了企巢。就用最簡單的例子來說吧,做的是一個登錄界面让蕾,輸入賬號和密碼浪规,賬號密碼輸入正確的話則提示登錄成功或听,反之則登錄失敗。效果圖如下

登陸界面

項(xiàng)目結(jié)構(gòu)

項(xiàng)目結(jié)構(gòu)

從項(xiàng)目結(jié)構(gòu)可以直接看出來罗丰,首先必須是要有實(shí)體類神帅,然后就是 Model 的接口和實(shí)例,里面便是業(yè)務(wù)類中的實(shí)現(xiàn)方法萌抵,還有就是 View 的接口和實(shí)例找御,里面是負(fù)責(zé) UI 的繪制和用戶進(jìn)行交互的邏輯,最后便是 Presenter绍填,這里面作為 Model 和 View 的中間協(xié)調(diào)部分,負(fù)責(zé)兩者之間的業(yè)務(wù)邏輯處理霎桅,復(fù)雜的邏輯處理一般都在這里進(jìn)行編寫。

實(shí)體類

首先是實(shí)體類的代碼讨永,實(shí)體類是必須有的就不用多說了

package com.example.xiaozhang.userloginactivity;
/** 
* Created by xiaozhang on 2016/11/3.
*/
//創(chuàng)建實(shí)體類滔驶,實(shí)體類必須有的!G淠帧揭糕!
public class UserBean {  
private String UserName;  
private String PassWord;  
public String getUserName() { 
return UserName;
}  
public void setUserName(String userName) {  
UserName = userName;  
 }  
public String getPassWord() {   
return PassWord; 
 }  
public void setPassWord(String passWord) {
PassWord = passWord;
  }
 }

Model

在 Model 中有一個業(yè)務(wù)的接口,處理邏輯交給 Presenter 就行了锻霎。

package com.example.xiaozhang.userloginactivity.Model;
import com.example.xiaozhang.userloginactivity.UserBean;
/** 
* Created by xiaozhang on 2016/11/3. 
*/
//Model接口------業(yè)務(wù)邏輯或者實(shí)體型接口
public interface IUserLoginModel {  
 void Login(UserBean mUserBean);
}

為了能讓點(diǎn)擊登錄后有提示著角,需要一個自定義 Listener 接口用來顯示在屏幕上作為提醒,代碼邏輯如下

package com.example.xiaozhang.userloginactivity.Model;
/** 
* Created by xiaozhang on 2016/11/3. 
*/
public interface IUserLoginListener {  
 void loginListener(boolean status);
}

最后是Model類中的業(yè)務(wù)類的邏輯編寫

package com.example.xiaozhang.loginactivity.Model;
import com.example.xiaozhang.loginactivity.UserBean;
/**
 *
 Created by xiaozhang on 2016/11/3. 
*/
public class UserLoginModel implements IUserLoginModel {  
private String UserName;
private String PassWord;  
private IUserLoginListener LoginListener;  
public UserLoginModel(IUserLoginListener loginListener){  
  this.LoginListener = loginListener;
  }  
@Override public void Login(UserBean mUserBean) {  
  boolean status = false;   
UserName = mUserBean.getUserName();    
PassWord = mUserBean.getPassWord();   
 if ("admin".equals(UserName)&&"123456".equals(PassWord))        
status = true;   
 LoginListener.loginListener(status); 
 }
}

View

View 和 Presenter 交互是通過接口的行形式旋恼,不過在寫這個接口之前需要想一想需要實(shí)現(xiàn)的功能有哪些吏口。
登錄功能上肯定要有用戶名和密碼

String getUserName();
String getPassWord();

重置功能上也是要有清除用戶名和密碼

void clearUserName();
void clearPassWord();

還有就是點(diǎn)擊登錄按鈕后顯示是否成功登錄的消息提示

void showMessage(String Message);

整合一下就是一個 View 接口的所有實(shí)現(xiàn)代碼了

package com.example.xiaozhang.userloginactivity.View;
/**
 * Created by xiaozhang on 2016/11/3.
 */
public interface IUserLoginActivity {  
String getUserName();  
String getPassWord();  
void clearUserName();  
void clearPassWord(); 
 void showMessage(String Message);
}

后面就是寫實(shí)現(xiàn)類了,前面說過了 Activity 對應(yīng)的就是 View 的實(shí)現(xiàn)類冰更,所以在 Activity中寫實(shí)現(xiàn)類的邏輯

package com.example.xiaozhang.userloginactivity.View;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;import android.widget.EditText;
import android.widget.Toast;
import com.example.xiaozhang.userloginactivity.Presenter.UserLoginPresenter;
import com.example.xiaozhang.userloginactivity.R;
public class UserLoginActivity extends AppCompatActivity implements IUserLoginActivity { 
 private EditText mInputUserName;  
private EditText mInputPassWord;  
private Button mLogin;  
private Button mReset;  
//這里需要注意下产徊,沒有 Presenter 的話前面這些都白寫了,所以一定要創(chuàng)建實(shí)例蜀细!
private UserLoginPresenter mUserLoginPresenter = new UserLoginPresenter(this);
  @Override  
protected void onCreate(Bundle savedInstanceState) {    
super.onCreate(savedInstanceState);   
 setContentView(R.layout.activity_main);  
  initView();  
}  
private void initView() {    
mInputUserName = (EditText) findViewById(R.id.edit_input_Account);  
mInputPassWord = (EditText) findViewById(R.id.edit_input_PassWord);   
 mLogin = (Button) findViewById(R.id.btn_Login);  
 mReset = (Button) findViewById(R.id.btn_Reset); 
 mLogin.setOnClickListener(new View.OnClickListener() {  
    @Override public void onClick(View view) {     
   //復(fù)雜的邏輯交給Presenter       
 mUserLoginPresenter.login();   
   }   
 });   
 mReset.setOnClickListener(new View.OnClickListener() {
      @Override public void onClick(View view) {  
      //復(fù)雜的邏輯交給presenter
        mUserLoginPresenter.Reset();  
    }   
 }); 
 }  
@Override public String getUserName() {  
  return mInputUserName.getText().toString(); 
 }  
@Override public String getPassWord() { 
   return mInputPassWord.getText().toString();
  }  
@Override public void clearUserName() {
    mInputUserName.setText(""); 
 } 
 @Override public void clearPassWord() { 
   mInputPassWord.setText(""); 
 }
  @Override  public void showMessage(String Message) {  
  Toast.makeText(this, Message, Toast.LENGTH_LONG).show();
  }
}

Presenter

前面也提到了 Presenter 是 View 和 Model 進(jìn)行交互的中間橋梁舟铜,這也要看你在你的代碼里需要實(shí)現(xiàn)的是什么功能,在這里實(shí)現(xiàn)的登錄和重置功能的實(shí)現(xiàn)以及點(diǎn)擊登錄后是否能成功登錄出現(xiàn)的提示消息

package com.example.xiaozhang.userloginactivity.Presenter;
import com.example.xiaozhang.userloginactivity.Model.IUserLoginModel;
import com.example.xiaozhang.userloginactivity.Model.IUserLoginListener;
import com.example.xiaozhang.userloginactivity.Model.UserLoginModel;
import com.example.xiaozhang.userloginactivity.UserBean;
import com.example.xiaozhang.userloginactivity.View.IUserLoginActivity;
/** 
* Created by xiaozhang on 2016/11/3. 
*/
public class UserLoginPresenter  implements IUserLoginListener{  
private IUserLoginModel mIUserLoginModel; 
 private IUserLoginActivity mIUserLoginActivity; 
 public UserLoginPresenter(IUserLoginActivity mIULoginActivity) {    
this.mIUserLoginActivity = mIULoginActivity;  //這里命名后來發(fā)現(xiàn)不好區(qū)分奠衔,所以改了深滚。。
  mIUserLoginModel = new UserLoginModel(this);  
}  
public void login() { 
 UserBean mUserBean = new UserBean();    
mUserBean.setUserName(mIUserLoginActivity.getUserName());    
mUserBean.setPassWord(mIUserLoginActivity.getPassWord());    
mIUserLoginModel.Login(mUserBean); 
 } 
 public void Reset() { 
   mIUserLoginActivity.clearPassWord();   
 mIUserLoginActivity.clearUserName(); 
 }  
@Override public void loginListener(boolean status) {  
  String Message;   
 if (status)      
Message= "登錄成功";  
  else    
  Message= "登錄失敗涣觉,請檢查賬號密碼是否正確";    
mIUserLoginActivity.showMessage(Message);  }
}

總結(jié)

以上便是我對MVP的初步認(rèn)識痴荐,畢竟自己也是剛接觸這個不久,所以寫的不好還請指導(dǎo)官册。對于剛接觸到MVP模式還是有很多的問題生兆,只能參考寫出這么一個簡單的Demo,后面也會從接觸到的項(xiàng)目中學(xué)習(xí)到MVP的用法,到時候也會寫出來和大家分享鸦难。

參考資料

對MVP說的比較詳細(xì)的文章
淺談MVP
Android MVP模式 簡單易懂的介紹方式

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末根吁,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子合蔽,更是在濱河造成了極大的恐慌击敌,老刑警劉巖,帶你破解...
    沈念sama閱讀 207,248評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件拴事,死亡現(xiàn)場離奇詭異沃斤,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)刃宵,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,681評論 2 381
  • 文/潘曉璐 我一進(jìn)店門衡瓶,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人牲证,你說我怎么就攤上這事哮针。” “怎么了坦袍?”我有些...
    開封第一講書人閱讀 153,443評論 0 344
  • 文/不壞的土叔 我叫張陵十厢,是天一觀的道長。 經(jīng)常有香客問我捂齐,道長蛮放,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 55,475評論 1 279
  • 正文 為了忘掉前任辛燥,我火速辦了婚禮筛武,結(jié)果婚禮上缝其,老公的妹妹穿的比我還像新娘挎塌。我一直安慰自己,他們只是感情好内边,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,458評論 5 374
  • 文/花漫 我一把揭開白布榴都。 她就那樣靜靜地躺著,像睡著了一般漠其。 火紅的嫁衣襯著肌膚如雪嘴高。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,185評論 1 284
  • 那天和屎,我揣著相機(jī)與錄音拴驮,去河邊找鬼。 笑死柴信,一個胖子當(dāng)著我的面吹牛套啤,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播随常,決...
    沈念sama閱讀 38,451評論 3 401
  • 文/蒼蘭香墨 我猛地睜開眼潜沦,長吁一口氣:“原來是場噩夢啊……” “哼萄涯!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起唆鸡,我...
    開封第一講書人閱讀 37,112評論 0 261
  • 序言:老撾萬榮一對情侶失蹤涝影,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后争占,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體燃逻,經(jīng)...
    沈念sama閱讀 43,609評論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,083評論 2 325
  • 正文 我和宋清朗相戀三年燃乍,在試婚紗的時候發(fā)現(xiàn)自己被綠了唆樊。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,163評論 1 334
  • 序言:一個原本活蹦亂跳的男人離奇死亡刻蟹,死狀恐怖逗旁,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情舆瘪,我是刑警寧澤揣非,帶...
    沈念sama閱讀 33,803評論 4 323
  • 正文 年R本政府宣布,位于F島的核電站虐杯,受9級特大地震影響膘魄,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜召调,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,357評論 3 307
  • 文/蒙蒙 一膨桥、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧唠叛,春花似錦只嚣、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,357評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至障般,卻和暖如春调鲸,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背挽荡。 一陣腳步聲響...
    開封第一講書人閱讀 31,590評論 1 261
  • 我被黑心中介騙來泰國打工藐石, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人定拟。 一個月前我還...
    沈念sama閱讀 45,636評論 2 355
  • 正文 我出身青樓于微,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子角雷,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,925評論 2 344

推薦閱讀更多精彩內(nèi)容