原文 http://zhengxiaopeng.com/2015/02/06/Android%E4%B8%AD%E7%9A%84MVP/
前言
MVP作為一種MVC的演化版本在Android開發中受到了越來越多的關注,但在項目開發中選擇一種這樣的軟件設計模式需保持慎重心態,一旦確定 使用MVP作為你App的開發模式那么你就最好堅持做下去,如果在使用MVP模式開發過程中發現問題而且坑越來越大,這時你想用MVC等來重新設計的話基 本上就等於推倒重來了。要知道在Android上MVP在現在為止並沒有統一的標准或者框架,不像SSH這三個成熟穩重強而有力的三劍客支持推動着 Java EE的開發,所以在運用MVP時一定要做好自己的理解,並且盡量預知自己App各模塊的需求(客戶說改改改,我們就改改改 :-( )以便提前做好充分的設計工作。當然MVP既然能出現那么必然有它的優點的,不然誰會理會這個冒出來的東西,下面就對Android中MVP做一些闡述。
MVP簡介
相信大家對MVC都是比較熟悉了:M-Model-模型、V-View-視圖、C-Controller-控制器,MVP作為MVC的演化版本,那么類似的MVP所對應的意義:M-Model-模型、V-View-視圖、P-Presenter-表示器。 從MVC和MVP兩者結合來看,Controlller/Presenter在MVC/MVP中都起着邏輯控制處理的角色,起着控制各業務流程的作用。而 MVP與MVC最不同的一點是M與V是不直接關聯的也是就Model與View不存在直接關系,這兩者之間間隔着的是Presenter層,其負責調控 View與Model之間的間接交互,MVP的結構圖如下所示,對於這個圖理解即可而不必限於其中的條條框框,畢竟在不同的場景下多少會有些出入的。在 Android中很重要的一點就是對UI的操作基本上需要異步進行也就是在MainThread中才能操作UI,所以對View與Model的切斷分離是 合理的。此外Presenter與View、Model的交互使用接口定義交互操作可以進一步達到松耦合也可以通過接口更加方便地進行單元測試。MVP結構圖
MVP之Model
模型這一層之中做的工作是具體業務邏輯處理的實現,都伴隨着程序中各種數據的處理,復雜一些的就明顯需要實現一個Interface來松耦合了。
MVP之View
視圖這一層體現的很輕薄,負責顯示數據、提供友好界面跟用戶交互就行。MVP下Activity和Fragment體現在了這一 層,Activity一般也就做加載UI視圖、設置監聽再交由Presenter處理的一些工作,所以也就需要持有相應Presenter的引用。例 如,Activity上滾動列表時隱藏或者顯示Acionbar(Toolbar),這樣的UI邏輯時也應該在這一層。另外在View上輸入的數據做一些 判斷時,例如,EditText的輸入數據,假如是簡單的非空判斷則可以作為View層的邏輯,而當需要對EditText的數據進行更復雜的比較時,如 從數據庫獲取本地數據進行判斷時明顯需要經過Model層才能返回了,所以這些細節需要自己掂量。
MVP之Presenter
Presenter這一層處理着程序各種邏輯的分發,收到View層UI上的反饋命令、定時命令、系統命令等指令后分發處理邏輯交由Model層做具體的業務操作。
演示demo
動手寫起代碼來才有更好的感覺。demo很簡單,還是上個圖更直觀,輸入城市的代號,點擊按鈕獲取城市的天氣信息然后顯示出來,網絡操作使用Volley框架,解析用Gson,其它的就手寫了。整個項目的包設計如下:
包結構
項目效果預覽
包 圖中明顯的三層:Model包、Presenter包、UI包,其中,三者都實現各自的結構,Model為WeatherModel、Presenter 為WeatherPresenter、View為Weather,那么具體實現類就是impl包里的了,View層的即為Activity。此外的app 和util包無關緊要可以不看。可以看到采用MVP設計后項目明顯多了很多東西,這也是不可避免的,使用原始方法可以使項目開起來簡單些但是以后還有維護 呢、測試呢、加功能呢、。。。
entity里的實體屬性基本上對應json里的這些屬性了,代碼不貼了,View里面的接口:
1 public interface WeatherView { 2 void showLoading(); 3 void hideLoading(); 4 void showError(); 5 void setWeatherInfo(Weather weather); 6 }
WeatherPresenter:
1 public interface WeatherPresenter { 2 /** 3 * 獲取天氣的邏輯 4 */ 5 void getWeather(String cityNO); 6 }
WeatherModel:
public interface WeatherPresenter { /** * 獲取天氣的邏輯 */ void getWeather(String cityNO); }
prestener里面還有個OnWeatherListener,其在Presenter層實現,給Model層回調,更改View層的狀態,確保 Model層不直接操作View層。如果沒有這一接口在WeatherPresenterImpl實現的話,WeatherPresenterImpl只 有View和Model的引用那么Model怎么把結果告訴View呢?當然這只是一種解決方案,在實際項目中可以使用Dagger、EventBus、 Otto等第三方框架結合進來達到更加松耦合的設計。
public interface OnWeatherListener { /** * 成功時回調 * * @param weather */ void onSuccess(Weather weather); /** * 失敗時回調,簡單處理,沒做什么 */ void onError(); }
所以demo的代碼流程:Activity做了一些UI初始化的東西並需要實例化對應WeatherPresenter的引用和實現 WeatherView的接口,監聽界面動作,Go按鈕按下后即接收到查詢天氣的事件,在onClick里接收到即通過WeatherPresenter 的引用把它交給WeatherPresenter處理。WeatherPresenter接收到了查詢天氣的邏輯就知道要查詢天氣了,然后把查詢天氣的具 體業務實現交給WeatherModel去實現同時把WeatherListener即WeatherPresenter自己傳給 WeatherModel。WeatherModel進行查詢天氣業務后即把結果通過WeatherListener回調通知 WeatherPresenter,WeatherPresenter再把結果返回給View層的Activity,最后Activity顯示結果。就這 樣,拍磚之處請拍。
End
采用哪種軟件設計模式都是為了達到如下目的,找到合適的加以運用就是最好的:
易於維護
易於測試
松耦合度
復用性高
健壯穩定
本文demo
Rocko’s MVP demo
MVP相關demo
androidmvp
ActivityFragmentMVP
EffectiveAndroidUI
MvpCleanArchitecture
Material-Movies
.