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代码换行好麻烦啊,有简单一点的操作吗
网友评论
打算对着敲一遍呢