像小白一樣學習MVP

MVP與MVC

MVP是從MVC的延伸。為什么要會出現MVP模式:那我們得了解一下MVC模式到底是一個怎樣的模式:
我們先看MVC模式:view層和model是直接溝通的,model是邏輯、業務、數據層。model這里面涉及到的東西特別多,包括:數據庫存儲、網絡數據獲取、文件數據讀取等;雖然MVC中也是主要將UI和業務邏輯及數據進行分離,而我們在使用MVC模式的時候也是將這些數據邏輯等封裝在單獨的類進行操作,但是這里面的還是太多。導致我們的activity成為了”萬能的activity“。
而這個時候我們看下MVP模式:

MVP和MVC對比圖

1:view和model層是分離的,他是通過presenter進行溝通。所以UI和邏輯、數據的交互都在presenter中。
2:因為view脫離了model層,所以activity將只要通過接口與presenter進行溝通,從而減少了大量的邏輯、數據代碼。


MVP的優點

1、模型與視圖完全分離,我們可以修改視圖而不影響模型;
2、可以更高效地使用模型,因為所有的交互都發生在一個地方——Presenter內部;
3、我們可以將一個Presenter用于多個視圖,而不需要改變Presenter的邏輯。這個特性非常的有用,因為視圖的變化總是比模型的變化頻繁;
4、如果我們把邏輯放在Presenter中,那么我們就可以脫離用戶接口來測試這些邏輯(單元測試)。


MVP實操

MVP中我覺得先寫M 然后寫V 再寫P。因為P是橋梁。
我們看下項目包架構

mvp項目包架構

我是根據每個功能來建立包名的,wificonfig是我寫的一個wifi配置功能,這里面的所有流程按照mvp框架來寫。所以里面分別建立了model、presenter、view包。我沒有將bean類放到這里面來是因為單獨拿出來可能會好找點,其實這個也沒那么重要。

mvp中的M

先說Model:數據邏輯層;主要處理數據的存取、邏輯的處理等。
model主要分為一個接口,一個類:這樣會簡潔。
首先看接口:
<pre>
<code>
public interface WIFIModel {

/* 獲取wifi列表  */    

void getWifiListInfo();    

/* 從網絡讀取wifi列表  */    

List<WifiInfoBean> loadWifiListInfo();    

  /*  判斷wifi是否打開  */    

boolean getWifiStatus();    

/*  設置wifi狀態   */    

boolean setWifiStatus(boolean isConn);

}
</code>
</pre>
主要提供你需要做的功能接口。我這里是設置wifi、獲取wifi列表。然后新建一個類實現此接口中的所有方法
<pre>
<code>
public class WIFIModelImp implements WIFIModel {

private static final String TAG = WIFIModelImp.class.getSimpleName();

private Context context = null;

/** 對象實例類及list實例 **/

private List wifiInfoBeanList = new ArrayList();

private List list = null;

private ScanResult mScanResult = null; //ScanResult類描述了一個已發現AP的信息。

private WifiAdmin wifiAdmin = null;

public WIFIModelImp(Context ctx){

context = ctx;

wifiAdmin = new WifiAdmin(context);

}

@Override

public void getWifiListInfo() {

}

@Override

public List loadWifiListInfo() {

list = wifiAdmin.getWifiList();

if(null != list && list.size() > 0){

for(int i=0; i<list.size(); i++){

    mScanResult = list.get(i);

    WifiInfoBean wifiInfoBean = new 
    WifiInfoBean(mScanResult.SSID,mScanResult.capabilities,mScanResult.level);
    wifiInfoBeanList.add(wifiInfoBean);

}

}

return wifiInfoBeanList;

}

@Override

public boolean getWifiStatus() {

  boolean isConn = wifiAdmin.isConn(context);

  return isConn;

}

@Override

public boolean setWifiStatus() {

  boolean isConn = wifiAdmin.isConn(context);

  if(isConn){

    //進行wifi關閉操作

      wifiAdmin.closeWifi();

      isConn = false;

    } else {

    //進行wifi打開操作

    wifiAdmin.openWifi();

    isConn = true;

    }

    return isConn;

}

}
</code>
</pre>
實現接口中的所有方法,然后再不同的方法,實現不同的功能邏輯處理。

mvp中的V

然后我們看V:主要做界面顯示。你會發現在這里所有的顯示都在這里用方法來實現。哪怕是一個text.settext()、img.setbackage();
<pre>
<code>
public interface WIFIView {

WifiInfoBean getWIFIInfo();

/** 顯示wifi開關狀態 **/

void showWifiConnStatus(boolean isConn);

/** list顯示 **/

void showRecyList(List list);

}
</code>
</pre>
其中activity也是屬于V中的一部分。

mvp中的P

然后我們看P:主要做為V視圖層和M邏輯層的橋梁。所有UI與數據的交互都通過P來進行,而同樣,都通過接口來實現
<pre>
<code>
public class WIFIPresenter {

private static final String TAG = WIFIPresenter.class.getSimpleName();

private Context ctx = null;

/* 實體類對象和list對象定義 */

private List wifiInfoBeanList = null;

/* 類對象的定義 */

private WIFIModel wifiModel = null;

private WIFIView wifiView = null;

private WIFIInfoAdapter wifiInfoAdapter = null;

public WIFIPresenter(Context context, WIFIView view){

ctx = context;

wifiView = view;

wifiModel = new WIFIModelImp(context);

}

/**
*@descriptoin 獲取wifi列表

*@author dc

*@param

*@date 2016/8/12 11:07

*@return wifi list

*/

public void loadWifiList(){

wifiInfoBeanList = wifiModel.loadWifiListInfo();

Log.e(TAG,"wifiList is size=" + wifiInfoBeanList.size());

if (null != wifiInfoBeanList && wifiInfoBeanList.size() > 0) {

      wifiView.showRecyList(wifiInfoBeanList);

}

}

/**
*@descriptoin 獲取wifi是否打開狀態

*@author dc

*@param

*@date 2016/8/12 11:09

*@return false:關閉 true:打開

*/

public boolean getIsWifiConn(){

return wifiModel.getWifiStatus();

}

/**
*@descriptoin 判斷wifi是否打開,并獲取wifi列表

*@author dc

*@param

*@date 2016/8/12 14:08

*@return

*/

public void getWifiList(){

/* 獲取wifi狀態:是否打開 */

boolean isWifiSwift = getIsWifiConn();

wifiView.showWifiConnStatus(isWifiSwift);

if(isWifiSwift) {

      //獲取wifi列表

      loadWifiList();

}

}

/**
*@descriptoin 設置wifi狀態

*@author dc

*@param

*@date 2016/8/12 14:16

*@return

*/

public void setWifiStatus(){

/* 設置wifi狀態 */

boolean isWifiSwift = wifiModel.setWifiStatus();

wifiView.showWifiConnStatus(isWifiSwift);

}

/**
*@descriptoin 清空list

*@author dc

*@param

*@date 2016/8/12 14:59

*@return

*/

public void clearWifiList(){

if(null != wifiInfoBeanList){

      wifiInfoBeanList.clear();

      wifiView.showRecyList(wifiInfoBeanList);

}

}
</code>
</pre>
我們可以看到P中的所有方法,都是通過V或M的接口來操作M或V。
比如:
<pre>
<code>
public void loadWifiList(){

wifiInfoBeanList = wifiModel.loadWifiListInfo();

Log.e(TAG,"wifiList is size=" + wifiInfoBeanList.size());

if (null != wifiInfoBeanList && wifiInfoBeanList.size() > 0) {

      wifiView.showRecyList(wifiInfoBeanList);

}

}
</code>
</pre>
獲取wifi列表屬于數據的讀取,我們在M中屬性此方法。
<pre>
<code>
wifiInfoBeanList = wifiModel.loadWifiListInfo();
</code>
</pre>
然后獲取數據list之后,需要展示在UI上,我們知道UI的顯示在V中實現
<pre>
<code>
wifiView.showRecyList(wifiInfoBeanList);
</code>
</pre>
這樣我們很容易的看到P 主要就是連接M和V。在M和V的交互中通過接口來起到橋梁的作用。
主要查看一下P的構造方法。
<pre>
<code>
public WIFIPresenter(Context context, WIFIView view){

ctx = context;

wifiView = view;

wifiModel = new WIFIModelImp(context);

}
</code>
</pre>
因為M有實現類,所以直接new 他的構造方法進行初始化。

mvp中的Activity或Fragment

而V主要是UI的展示。他主要是在activity或fragment中進行展示,所以我們在activity中需要impments V的接口
<pre>
<code>

public class WIFIConfigActivity extends AppCompatActivity implements WIFIView ,View.OnClickListener{

@Override

public WifiInfoBean getWIFIInfo() {

    return null;

}

@Override

public void showWifiConnStatus(boolean isConn) {

  Log.e(TAG, "wifi是否打開:" + isConn);

  if(!isConn){
   //wifi 已關閉
    activityWificonfigSwitchImg.setBackgroundResource(R.drawable.switch_off);

} else {

    //wifi 已打開
    activityWificonfigSwitchImg.setBackgroundResource(R.drawable.switch_on);

}

}

@Override

public void showRecyList(List list) {

wifiInfoAdapter = new WIFIInfoAdapter(WIFIConfigActivity.this, list);

activityWificonfigListRv.setAdapter(wifiInfoAdapter);
}

}
</code>
</pre>
其中activity實現了view,并實現了他的所有方法。然后再對應的方法中實現UI展示

<pre>
<code>
@Override

public void showRecyList(List list) {

wifiInfoAdapter = new WIFIInfoAdapter(WIFIConfigActivity.this, list);

activityWificonfigListRv.setAdapter(wifiInfoAdapter);

}
</code>
</pre>
得到list之后再此方法中顯示Adapter的適配。
<pre>
<code>
private WIFIPresenter wifiPresenter = null;

wifiPresenter = new WIFIPresenter(WIFIConfigActivity.this, WIFIConfigActivity.this);
</code>
</pre>
其中需要創建一個P來作為橋梁來交互M和V。
如:
<pre>
<code>
//獲取wifi列表

wifiPresenter.getWifiList();
</code>
</pre>


總結:
MVP:個人覺得他的優點還是蠻多的。
1:他讓我的act很簡潔,act不再是“萬能的”。
2:然后數據和界面的交互是獨立的,修改界面不影響數據,修改數據不影響界面。對于單元測試特方便。
3:所有的交互都在P中,方便我們查找問題


M:主要做數據和邏輯處理。最好通口和實現類的方式實現。在M中,我們可以處理數據的存儲,讀取、獲取數據獲取、提交、數據庫操作等。達到了數據與視圖的分離,數據的集中管控的效果。
V:主要做界面的顯示:哪怕是一個textview的顯示,listview的顯示等所有與界面相關的都可以在V中通過接口來實現。開始我以為V的作用并不大,因為我們在act中顯示界面其實也沒什么復雜的,代碼也不會很多。但是只要結合MVP模式來看的話,還是很震驚的。個人理解他主要是讓act不存在任何的邏輯處理,什么時候顯示界面,什么時候不顯示都不用act來控制。都用P來統一規范。
P:主要處理M與V的交互。P作為橋梁很好理解他就是通過獲取M數據來控制V的顯示,或者通過獲取V數據來保存到M中做數據邏輯處理。所以P的作用還是蠻大的。程序只要出了問題,直接中P中對應的方法找,然后查看P是調用的那個M或V,對查找問題我也覺得是很方便的。


小白初步學習MVP,以上也只是個人的MVP的了解,肯定有不對之處,還請多多指教。
PS:markdown代碼換行好麻煩啊,有簡單一點的操作嗎

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容