在Android当中,相比传统的MVC设计模式,View层(视图层)对应的是Android当中的布局文件。而布局文件是用XML格式来写的。但是这个XML布局文件它并不像Java Web端那么强大,能做的事情非常有限。而Controller所对应的Activity这个类,它不仅要处理业务逻辑,同时它也要处理Android当中的一些操作UI的功能。我们在实际项目开发过程中,有很多UI操作的逻辑写在Activity当中。这就导致Controller层中充斥了很多View层应当做的内容,从而使得Controller层非常冗余厚重。为了改善这一点,我们引入了MVP的架构模式。
2.MVP定义<1>M:依然是业务逻辑和实体模型。
<2>V:对应于Activity,负责View的绘制以及与用户交互。
<3>P:负责完成VIew与Model间的交互。
3.MVP的优点相较于MVC,MVP加入了Presenter层,我们便可以把之前Activity中作为Controller层的内容抽出来放入Presenter层,Activity则可以彻底加入View层了。这样我们也就完全切断了View层与Model层之间的联系。Activity与XML作为View层只对如何操作UI、渲染数据到界面上关心,而Model层则只关心如何获取数据源。至于数据源的二次处理以及数据注入UI则由Presenter关心,彻底切断数据与界面渲染。
4.MVP实例讲解根据实例我们学习一下MVP,顺手搭建一套MVP的框架
首先是View层,我们先定义一个接口
public interface MvpbaseIView {
}
这个接口基类其实是为了一会儿多个类的关联使用,里面是没有代码的。
接着是Activity的基类
public abstract class MvpbaseActivityextends AppCompatActivity{ protected Bundle savedInstanceState; protected T mPresenter; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); //在界面未初始化之前调用的初始化窗口 initWindows(); if (initArgs(getIntent().getExtras())) { this.savedInstanceState = savedInstanceState; requestWindowFeature(Window.FEATURE_NO_TITLE); setContentView(getContentLayoutId()); initWidget(); mPresenter = getPresenterImpl(); initData(); } else { finish(); } } protected void initWindows() { } protected boolean initArgs(Bundle bundle) { return true; } protected abstract int getContentLayoutId(); protected void initWidget() { } protected void initData() { } protected abstract T getPresenterImpl(); }
这样View层的两个基类就都有了。
接下来是Model层的两个
Model层回调接口基类
public interface MvpbaseCallBack {
}
Model层接口基类
public interface MvpbaseIModel {
}
Model基类
public class MvpbaseModel{ protected T callback; protected Context context; public MvpbaseModel(Context context, T callback) { this.context = context; this.callback = callback; } }
最后就是我们的Presenter层
Presenter接口基类
public interface MvpbaseIPresenter {
}
Presenter基类
public abstract class MvpbasePresenter{ protected T mModel; protected U iView; public MvpbasePresenter(Context context,U mView) { mModel = getModelImp(); iView = mView; } protected abstract T getModelImp(); }
这样基类就完成了。我们可以看到,Activity中持有Presenter的对象,而Presenter中又持有IView和Model的对象。这样三者就联系在了一起。但是Activity和Model之间却没有直接的关联。
接下来是我们对于基类的使用。
首先先上一个实体类,模拟网络请求返回的实体
public class Entity {
private String str;
private int hide;
public Entity(String str, int hide) {
this.str = str;
this.hide = hide;
}
public String getStr() {
return str;
}
public void setStr(String str) {
this.str = str;
}
public int getHide() {
return hide;
}
public void setHide(int hide) {
this.hide = hide;
}
}
接着就是我们的View层两大件
public interface DemoIView extends MvpbaseIView {
void showText(String str);
void showView();
void hideView();
String getXText();
}
这里可以看到View层接口我定义了四个动作,分别是显隐控件和设置获取TextView上的文字,这个要根据具体页面设置。
public class DemoActivity extends MvpbaseActivityimplements DemoIView{ private TextView tv_center; private View view_gang; @Override protected int getContentLayoutId() { return R.layout.activity_main; } @Override protected void initWidget() { tv_center = findViewById(R.id.tv_center); view_gang = findViewById(R.id.view_gang); } @Override protected void initData() { mPresenter.getData(); } @Override protected DemoIPresenter getPresenterImpl() { return new DemoPresenter(this,this); } @Override public void showText(String str) { tv_center.setText(str); } @Override public void showView() { view_gang.setVisibility(View.VISIBLE); } @Override public void hideView() { view_gang.setVisibility(View.GONE); } @Override public String getXText() { return tv_center.getText().toString().trim(); } }
Activity实现了IView的接口,并且实现了里面的接口方法,将定义的动作表现在了界面上。这里注意,我们在getPresenterImpl中返回了Presenter类的实例,并且该Activity还实现了IView接口。
下来便是我们的Model层
public interface DemoCallback extends MvpbaseCallBack {
void success(Entity entity);
void failure();
}
Callback中规中矩,还是成功和失败两个接口。
接着是Model接口类
public interface DemoIModel extends MvpbaseIModel {
void getData(String strEnter);
}
Model实现类
public class DemoModel extends MvpbaseModelimplements DemoIModel { public DemoModel(Context context, DemoCallback callback) { super(context, callback); } @Override public void getData(String strEnter) { try { new Thread().sleep(2000); if (strEnter.equals("11111")){ //成功 callback.success(new Entity("xixixxi",0)); }else{ //失败 callback.failure(); } } catch (InterruptedException e) { e.printStackTrace(); } } }
Model类中我们在getData方法中模拟了一个网络请求,并进行了回调。
这样我们的Model层也编写完成了。
下来就是Presenter层了。
我们先进行接口设计
public interface DemoIPresenter extends MvpbaseIPresenter {
void getData();
}
由于我们只有一个获取界面数据的需求,所以这里只定义了一个接口方法
public class DemoPresenter extends MvpbasePresenterimplements DemoIPresenter,DemoCallback{ private Context mContext; public DemoPresenter(Context context, DemoIView mView) { super(context, mView); mContext = context; } @Override protected DemoIModel getModelImp() { return new DemoModel(mContext,this); } @Override public void success(Entity entity) { iView.showText(entity.getStr()); if (entity.getHide() == 0) { iView.hideView(); }else{ iView.showView(); } } @Override public void failure() { ToastUtil.toastWord(mContext,"错误"); } @Override public void getData() { mModel.getData(iView.getXText()); } }
在Presenter的实现类中,一方面是刚才我们定义的接口方法getData中调用了Model层的方法。另一方面是我们在回调中调用了IView接口中方法对界面进行了操作。当然还有在getModelImp中返回我们创建的Model类实例。这就是一套完整的MVP设计模式。我个人觉得MVP除了解耦,最大的魅力就是开发的不耽误功夫。我们可以先进行界面的开发,将界面可能需要的工作提前都设置好,比如给TextView设置文本,从Edittext获取值,根据变量显隐控件,按钮需要的点击事件等,都可以提前设置好对应的方法。接着等接口出来我们就可以很快对接接口,并将数据设置进去。不影响之前的界面,方便快捷,思路清晰。



