像小白一样学习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代码换行好麻烦啊,有简单一点的操作吗

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 218,284评论 6 506
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 93,115评论 3 395
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 164,614评论 0 354
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,671评论 1 293
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,699评论 6 392
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,562评论 1 305
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,309评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,223评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,668评论 1 314
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,859评论 3 336
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,981评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,705评论 5 347
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,310评论 3 330
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,904评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,023评论 1 270
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,146评论 3 370
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,933评论 2 355

推荐阅读更多精彩内容