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