轉:http://blog.csdn.net/qq_31852701/article/details/52946127java
首先MVP 是從經典的MVC架構演變而來,那咱們是否是要先說下何爲MVC模式?面試
系統C/S(Client/Server)三層架構模型:正則表達式
1)視圖層(View):通常採用XML文件對應用的界面進行描述,使用的時候能夠直接引入,極爲方便,能夠的大大縮短開發時間,也可使用JavaScript+HTML等的方式做爲View層,固然這裏須要進行Java和JavaScript之間的通訊,幸運的是,Android提供了很是方便的通訊實現。業務邏輯層(BLL):它的關注點主要集中在業務規則的制定、業務流程的實現等與業務需求有關的系統設計,也便是說它是與系統所應對的領域(Domain)邏輯有關,不少時候,也將業務邏輯層稱爲領域層。數據庫
2)控制層(Controller):Android的控制層的重任一般落在了衆多的Acitvity的肩上,這句話也就暗含了不要在Acitivity中寫代碼,要經過Activity交割Model業務邏輯層處理。編程
3)模型層(Model):對數據庫的操做、以及其餘和數據有關的的操做都應該在Model裏面處理,固然對業務計算等操做也是必須放在的該層的。就是應用程序中二進制的數據。設計模式
三層結構架構三層間的交互及做用以下圖所示:緩存
傳統的MVC模式是很不錯,咱們也很熟悉,畢竟用了這麼多年了。(忽然想到以前去一家公司面試他問個HelloWord的Android項目是否是MVC,我說不是,他說回答錯誤,阿西吧!)網絡
在Android項目上你會發現Activity的責任過重,什麼東西都要放在Activity中,最終致使了Activity太過臃腫。雖然能抽的都抽出來了,可是會發現代碼仍是不少,試想下上千行代碼尚未註釋,能不暈?即便是本身寫的,過些日子去看也有些暈暈的吧?架構
尤爲代碼敲完,一個月後需求又改了,從600、700行代碼中找到要修改的地方也是要一點功夫的。框架
爲了給Activity減輕壓力,這時候MVP出現了!
MVP有什麼好處,爲何要用MVP呢?
網上搜下一大堆MVP的各類好處,寶寶總結下主要有如下幾點:
下面開始貼代碼講解
先來說View IBuyBookView
這裏主要是包含了Activity的一系列關於UI操做,而後用咱們的Activity是實現,這樣Presenter就能夠調用了。
public interface IBuyBookView { /** * 提示toast */ void showToast(String msg); /** * 刷新adapter */ void refreshAdapter(); void onEmpty(); }
接下來說Model IBuyBookModel BuyBookModel
主要是寫了幾個方法供BuyBookModel去實現
這裏實現了IBuyBookModel,而後模擬了下網絡請求,用隨機來模擬請求成功與失敗,因此若是有童鞋下載Demo發現進去怎麼空白一片,那麼請退出來多近幾回,寶寶曾連續5次進去都是空白的,這運氣也太背了吧。
這裏貼上樓上那個回調接口,這裏用了泛型,爲何呢?爲了多多複用。
public interface ValueCallBack<T> { void onSuccess(T t); void onFail(String code); }
接下來說Presenter BasePresenter IBuyBookPresenterBuyBookPresenter
這個是全部Presenter的基類,裏面有個initData()方法,基本每一個Presenter都要處理網絡請求吧,因此我就弄了這麼一個基類,至於爲何是抽象的而不是接口,這是由於抽象方便點吧,若是咱們往抽象類中添加新的方法(該方法不是抽象的),能夠給他提供默認的實現,並且不要修改現有的代碼,可是若是是接口的話,就要修改現有的代碼了。指不定咱們之後要往這裏加什麼呢。
這裏爲何用了個泛型?爲了讓人一看這個Presenter就知道這對應着哪一個Activity,實際上這能夠不加的,可是我以爲加上去更好。便於後來人也便於本身之後再來修改這個類。
public abstract class BasePresenter<T extends BaseActivity> { abstract void initData(); }
這裏主要寫了個方法,以供BuyBookPresenter實現
public interface IBuyBookPresenter { List<BuyBookBean> getAdapterData(); }
這裏首先實現現了IBuyBookPresenter繼承了BasePresenter,而後重寫一些方法。這裏的構造方法是重點,在構造方法中,咱們須要傳入一個IBookView,實際上咱們的Activity已經實現IBookView了,因此這裏實際上傳的是具體的Activity,也就是this就好了。而後model咱們能夠直接new出來用,這裏就new了。
在initData中咱們是進行了具體的網絡請求,網絡請求咱們是否是要彈一個Dialog出來,直接在這mView.loading();調用就好了。而後請求成功onSuccess()裏面讓Dialog消失,提醒適配器刷新。失敗的話onFail()裏面提示Dialog消失,而後ListView設置失敗頁面什麼的。
public class BuyBookPresenter extends BasePresenter<BuyBookActivity> implements IBuyBookPresenter { private IBuyBookView mView; private IBuyBookModel mModel; public BuyBookPresenter(IBuyBookView iBuyBookView) { this.mView = iBuyBookView; this.mModel = new BuyBookModel(); } @Override public List<BuyBookBean> getAdapterData() { return mModel.getAdapterData(); } @Override public void initData() { //在這裏彈出loading mModel.getTestData(new ValueCallBack<List<BuyBookBean>>() { @Override public void onSuccess(List<BuyBookBean> buyBookBeen) { //在這裏取消loading //簡單數據操做能夠在presenter裏完成 mModel.getAdapterData().addAll(buyBookBeen); mView.refreshAdapter(); } @Override public void onFail(String code) { //在這裏取消loading mView.showToast(code); mView.onEmpty(); } }); } }
接下來說咱們的Activity BuyBookActivity BaseActivity
這是咱們Acticity的基類,能夠看到這裏有個泛型,注意了,前方高能。這個泛型還必須繼承BasePresenter,這個首先爲了讓人一看到這個Activity就知道對應着那個Presenter;其次最重要的就是爲了下面那個成員變量basepresenter,咱們寫一個抽象的方法要求返回泛型T,而這個泛型T又繼承了BasePresenter,那麼咱們就獲得了具體Presenter的成員變量,能夠直接用這個成員變量來調用Presenter中的方法了。
這個就是最終具體的Activity了,能夠看到這裏都沒什麼邏輯,基本都是一些重寫的方法。
public class BuyBookActivity extends BaseActivity<BuyBookPresenter> implements IBuyBookView { private ListView mListView; private BuyBookAdapter mAdapter; @Override BuyBookPresenter initPresent() { return new BuyBookPresenter(this); } @Override int getLayout() { return R.layout.activity_main; } @Override void initView() { mListView = (ListView) findViewById(R.id.listview); } @Override void onPrepare() { mAdapter = new BuyBookAdapter(this, basepresenter.getAdapterData()); mListView.setAdapter(mAdapter); basepresenter.initData(); } @Override public void showToast(String msg) { Toast.makeText(this, msg, Toast.LENGTH_SHORT).show(); } @Override public void refreshAdapter() { mAdapter.notifyDataSetChanged(); } public void onEmpty() { mListView.setEmptyView(null); } }
最後雖然MVP模式有許多好處,可是有一個致命的缺點就是類太多,原本一個類最多變成了7個類,最少變成6個類(使用Contract協議類)。因此並非全部的頁面都要用MVP模式的,很簡單的頁面就不必了,浪費時間是否是。
爲何MVP模式利於單元測試?
Presenter將邏輯和UI分開了,裏面沒有Android代碼,都是純純的java代碼。咱們能夠直接對Presenter寫Junit測試