前言
MVP作為一種MVC的演化版本在Android開(kāi)發(fā)中受到了越來(lái)越多的關(guān)注,但在項(xiàng)目開(kāi)發(fā)中選擇一種這樣的軟件設(shè)計(jì)模式需保持慎重心態(tài),一旦確定 使用MVP作為你App的開(kāi)發(fā)模式那么你就最好堅(jiān)持做下去,如果在使用MVP模式開(kāi)發(fā)過(guò)程中發(fā)現(xiàn)問(wèn)題而且坑越來(lái)越大,這時(shí)你想用MVC等來(lái)重新設(shè)計(jì)的話基 本上就等于推倒重來(lái)了。要知道在Android上MVP在現(xiàn)在為止并沒(méi)有統(tǒng)一的標(biāo)準(zhǔn)或者框架,不像SSH這三個(gè)成熟穩(wěn)重強(qiáng)而有力的三劍客支持推動(dòng)著 Java EE的開(kāi)發(fā),所以在運(yùn)用MVP時(shí)一定要做好自己的理解,并且盡量預(yù)知自己App各模塊的需求(客戶說(shuō)改改改,我們就改改改 :-( )以便提前做好充分的設(shè)計(jì)工作。當(dāng)然MVP既然能出現(xiàn)那么必然有它的優(yōu)點(diǎn)的,不然誰(shuí)會(huì)理會(huì)這個(gè)冒出來(lái)的東西,下面就對(duì)Android中MVP做一些闡述。
MVP簡(jiǎn)介
相信大家對(duì)MVC都是比較熟悉了:M-Model-模型、V-View-視圖、C-Controller-控制器,MVP作為MVC的演化版本,那么類似的MVP所對(duì)應(yīng)的意義:M-Model-模型、V-View-視圖、P-Presenter-表示器。 從MVC和MVP兩者結(jié)合來(lái)看,Controlller/Presenter在MVC/MVP中都起著邏輯控制處理的角色,起著控制各業(yè)務(wù)流程的作用。而 MVP與MVC最不同的一點(diǎn)是M與V是不直接關(guān)聯(lián)的也是就Model與View不存在直接關(guān)系,這兩者之間間隔著的是Presenter層,其負(fù)責(zé)調(diào)控 View與Model之間的間接交互,MVP的結(jié)構(gòu)圖如下所示,對(duì)于這個(gè)圖理解即可而不必限于其中的條條框框,畢竟在不同的場(chǎng)景下多少會(huì)有些出入的。在 Android中很重要的一點(diǎn)就是對(duì)UI的操作基本上需要異步進(jìn)行也就是在MainThread中才能操作UI,所以對(duì)View與Model的切斷分離是 合理的。此外Presenter與View、Model的交互使用接口定義交互操作可以進(jìn)一步達(dá)到松耦合也可以通過(guò)接口更加方便地進(jìn)行單元測(cè)試。

MVP之Model
模型這一層之中做的工作是具體業(yè)務(wù)邏輯處理的實(shí)現(xiàn),都伴隨著程序中各種數(shù)據(jù)的處理,復(fù)雜一些的就明顯需要實(shí)現(xiàn)一個(gè)Interface來(lái)松耦合了。
MVP之View
視圖這一層體現(xiàn)的很輕薄,負(fù)責(zé)顯示數(shù)據(jù)、提供友好界面跟用戶交互就行。MVP下Activity和Fragment體現(xiàn)在了這一 層,Activity一般也就做加載UI視圖、設(shè)置監(jiān)聽(tīng)再交由Presenter處理的一些工作,所以也就需要持有相應(yīng)Presenter的引用。例 如,Activity上滾動(dòng)列表時(shí)隱藏或者顯示Acionbar(Toolbar),這樣的UI邏輯時(shí)也應(yīng)該在這一層。另外在View上輸入的數(shù)據(jù)做一些 判斷時(shí),例如,EditText的輸入數(shù)據(jù),假如是簡(jiǎn)單的非空判斷則可以作為View層的邏輯,而當(dāng)需要對(duì)EditText的數(shù)據(jù)進(jìn)行更復(fù)雜的比較時(shí),如 從數(shù)據(jù)庫(kù)獲取本地?cái)?shù)據(jù)進(jìn)行判斷時(shí)明顯需要經(jīng)過(guò)Model層才能返回了,所以這些細(xì)節(jié)需要自己掂量。
MVP之Presenter
Presenter這一層處理著程序各種邏輯的分發(fā),收到View層UI上的反饋命令、定時(shí)命令、系統(tǒng)命令等指令后分發(fā)處理邏輯交由Model層做具體的業(yè)務(wù)操作。
先說(shuō)說(shuō)這個(gè)MVP的程序架構(gòu)吧,他不同于MVC。
首先MVP(Model View Presenter)Presenter的出現(xiàn),將Actvity視為View層,Presenter負(fù)責(zé)完成View層與Model層的交互。現(xiàn)在是這樣的:
- View 對(duì)應(yīng)于Activity,負(fù)責(zé)View的繪制以及與用戶交互
- Model 依然是業(yè)務(wù)邏輯和實(shí)體模型
- Presenter 負(fù)責(zé)完成View于Model間的交互
其實(shí)最明顯的區(qū)別就是,MVC中是允許Model和View進(jìn)行交互的,而MVP中很明顯,Model與View之間的交互由Presenter完成。還有一點(diǎn)就是Presenter與View之間的交互是通過(guò)接口的。
Retrofit+Rxjava+OKhttp:
一套網(wǎng)絡(luò)框架:現(xiàn)在Android 市面上很火的當(dāng)然是 Retrofit+RxJava + OkHttp, 功能強(qiáng)大,簡(jiǎn)單易用,因此在項(xiàng)目中我選用這套方案來(lái)作為網(wǎng)絡(luò)庫(kù)。
首先簡(jiǎn)單的說(shuō)一下:
Retrofit: Retrofit是Square 公司開(kāi)發(fā)的一款正對(duì)Android 網(wǎng)絡(luò)請(qǐng)求的框架。底層基于OkHttp 實(shí)現(xiàn),OkHttp 已經(jīng)得到了google 官方的認(rèn)可,
retrofit是由square公司開(kāi)發(fā)的。square在github上發(fā)布了很多優(yōu)秀的Android開(kāi)源項(xiàng)目。
OkHttp: 也是Square 開(kāi)源的網(wǎng)絡(luò)請(qǐng)求庫(kù)
RxJava:讓異步操作變得非常簡(jiǎn)單。
各自的職責(zé):Retrofit 負(fù)責(zé)請(qǐng)求的數(shù)據(jù)和請(qǐng)求的結(jié)果,使用接口的方式呈現(xiàn),OkHttp 負(fù)責(zé)請(qǐng)求的過(guò)程,RxJava 負(fù)責(zé)異步,各種線程之間的切換RxJava + Retrofit + okHttp 已成為當(dāng)前Android 網(wǎng)絡(luò)請(qǐng)求最流行的方式
演示demo
動(dòng)手寫(xiě)起代碼來(lái)才有更好的感覺(jué)。demo很簡(jiǎn)單,還是上個(gè)圖更直觀,輸入城市的代號(hào),點(diǎn)擊按鈕獲取城市的天氣信息然后顯示出來(lái),網(wǎng)絡(luò)操作使用Volley框架,解析用Gson,其它的就手寫(xiě)了。整個(gè)項(xiàng)目的包設(shè)計(jì)如下:


圖中明顯的三層:Model包、Presenter包、UI包,其中,三者都實(shí)現(xiàn)各自的結(jié)構(gòu),Model為WeatherModel、Presenter 為WeatherPresenter、View為Weather,那么具體實(shí)現(xiàn)類就是impl包里的了,View層的即為Activity。此外的app 和util包無(wú)關(guān)緊要可以不看??梢钥吹讲捎肕VP設(shè)計(jì)后項(xiàng)目明顯多了很多東西,這也是不可避免的,使用原始方法可以使項(xiàng)目開(kāi)起來(lái)簡(jiǎn)單些但是以后還有維護(hù) 呢、測(cè)試呢、加功能呢、。。。entity里的實(shí)體屬性基本上對(duì)應(yīng)json里的這些屬性了,代碼不貼了,View里面的接口:
public interface WeatherView {
void showLoading();
void hideLoading();
void showError();
void setWeatherInfo(Weather weather);
}
WeatherPresenter的接口:
public interface WeatherPresenter {
/**
* 獲取天氣的邏輯
*/
void getWeather(String cityNO);
}
WeatherModel接口:
public interface WeatherModel {
void loadWeather(String cityNO, OnWeatherListener listener);
}
prestener里面還有個(gè)OnWeatherListener,其在Presenter層實(shí)現(xiàn),給Model層回調(diào),更改View層的狀態(tài),確保 Model層不直接操作View層。如果沒(méi)有這一接口在WeatherPresenterImpl實(shí)現(xiàn)的話,WeatherPresenterImpl只 有View和Model的引用那么Model怎么把結(jié)果告訴View呢?當(dāng)然這只是一種解決方案,在實(shí)際項(xiàng)目中可以使用Dagger、EventBus、 Otto等第三方框架結(jié)合進(jìn)來(lái)達(dá)到更加松耦合的設(shè)計(jì)。
public interface OnWeatherListener {
/**
* 成功時(shí)回調(diào)
*
* @param weather
*/
void onSuccess(Weather weather);
/**
* 失敗時(shí)回調(diào),簡(jiǎn)單處理,沒(méi)做什么
*/
void onError();
}
所以demo的代碼流程:Activity做了一些UI初始化的東西并需要實(shí)例化對(duì)應(yīng)WeatherPresenter的引用和實(shí)現(xiàn) WeatherView的接口,監(jiān)聽(tīng)界面動(dòng)作,Go按鈕按下后即接收到查詢天氣的事件,在onClick里接收到即通過(guò)WeatherPresenter 的引用把它交給WeatherPresenter處理。WeatherPresenter接收到了查詢天氣的邏輯就知道要查詢天氣了,然后把查詢天氣的具 體業(yè)務(wù)實(shí)現(xiàn)交給WeatherModel去實(shí)現(xiàn)同時(shí)把WeatherListener即WeatherPresenter自己傳給 WeatherModel。WeatherModel進(jìn)行查詢天氣業(yè)務(wù)后即把結(jié)果通過(guò)WeatherListener回調(diào)通知 WeatherPresenter,WeatherPresenter再把結(jié)果返回給View層的Activity,最后Activity顯示結(jié)果。就這 樣,拍磚之處請(qǐng)拍。
總結(jié)
采用哪種軟件設(shè)計(jì)模式都是為了達(dá)到如下目的,找到合適的加以運(yùn)用就是最好的:
易于維護(hù)
易于測(cè)試
松耦合度
復(fù)用性高
健壯穩(wěn)定
本文demo
Rocko’s MVP demo
MVP相關(guān)
androidmvp
ActivityFragmentMVP
EffectiveAndroidUI
MvpCleanArchitecture
Material-Movies