网上关于MVP的冗长教程已经很多了,自己结合所做的MVP项目尽量简洁,简单,大白话的方式记录心得,为了日后遗忘的差不多了能迅速把记忆抓起来。一图胜千言,先上图。图1是mvp的框架流程图:
图1
简单介绍下MVP三剑客:Model,View, Presenter,重点会结合Demo去剖析。
Model: 它是涉及数据管理的接口,简单的说,只要是代码处理数据,都会由这个Model来负责。
View: 你能看到的都是View , 作为用户能看到手机上的界面都是View视图层,作用仅仅是绘制UI元素和响应UI操作,比如点击UI元素。
Presenter: Presenter是三剑客的核心部分,app的逻辑代码基本全写在Presenter中了,从图1就能看出来,它承上启下,联系着Model层和View层
需要注意的是,View层不和Model层直接联系,需要Presenter为中介,上面说的理论毕竟有些泛泛之谈,结合下面的Demo继续具体的分析。
图2
Demo实现的效果很简单,点击界面上的搜索按钮,会发送http协议获取某个城市的经纬度,当获取到http请求回执后,反序列化Json,然后重新绘制界面,显示经纬度。从MVP的模式去讲,这个包含搜索Button的,点击搜索后弹出的转圈等待界面就是View层,当响应点击事件之后,View层就会通知Presenter层,让Presenter去发送获取经纬度的http协议,并且在Presenter中监听http协议的回执,若协议收发成功,那么presenter就会通知View层去重新绘制UI。下面贴出具体代码进行理解
/**
* Created by xjc on 2018/11/26.
*/
public interface MainPresenter {
interface View extends BaseView {
//通知界面(View层)刷新的逻辑函数
void refreshViewMistakeIntruductionList( LocationResponseBean bean);
}
interface Model {
//发送获取经纬度坐标协议
void getLonLat();
}
}
一个Presenter是由两部分组成的:Presenter接口和Presenter的具体实现(Impl),Presenter接口中包含了两个interface:View和Model。 View接口的抽象方法就是声明了Presenter层和View层之间的联系,要和View之间有怎样的交互,比如上面View接口中的方法就是通知界面刷新。Model接口就是MVP中Model层要实现的功能,上述代码Model层中抽象方法就是为了发送经纬度的http协议。这样一目了然,这个Presenter的功能有两个,一是获取经纬度,二是通知界面重绘,但是具体怎么干,怎么一点点写出来,都会交给这个Presenter接口的实现类。
/**
* Created by xjc on 2018/11/26.
*/
public class MainPresenterImpl extends BasePresenter<MainPresenter.View> implements MainPresenter.Model{
private ApiHttpService apiHttpService;
@Inject
public MainPresenterImpl(ApiHttpService apiHttpService) {
this.apiHttpService = apiHttpService;
}
@Override
public void getLonLat() {
JSONObject jsonObject = new JSONObject();
try {
jsonObject.put("a","大连");
} catch (JSONException e) {
e.printStackTrace();
}
//retrofit2.0发送http请求
invoke(apiHttpService.fetchLocation(jsonObject.toString()),new Callback<LocationResponseBean>(){
@Override
public void onResponse(LocationResponseBean bean){
mView.refreshViewMistakeIntruductionList(bean);
}
});
}
}
可以看到实现类继承并实现了presenter接口中的View和Model接口,若协议收发成功,那么会调Presenter接口中View interface的方法,来通知界面该做一些XX操作了
mView.refreshViewMistakeIntruductionList(bean);
下面来看一下主界面(View层)
/**
* Created by xjc on 2018/11/26.
*/
public class MainActivity extends IBaseActivity<MainPresenterImpl> implements MainPresenter.View {
private Toast mToast = null;
@BindView(R.id.tv_location)
TextView tv_location;
@BindView(R.id.btn_search)
Button btn_search;
@Override
protected int getLayoutId() {
return R.layout.activity_main;
}
@Override
protected void loadData() {
}
@Override
protected void initView() {
}
@Override
protected void initInject() {
DaggerMainComponent.builder().apiHttpModule(new ApiHttpModule()).build().injectMain(this);
}
@Override
public void refreshViewMistakeIntruductionList(LocationResponseBean bean) {
//获取到数据,取消转圈
dismiss();
//重绘text
tv_location.setText(bean.getLat()+","+bean.getLon());
}
@OnClick(R.id.btn_search)
public void searchLocation(View view) {
//发送http请求
mPresenter.getLonLat();
//转圈等待
createLoading();
}
@Override
public void setState(int state) {
}
}
可以看到主界面只实现了Presenter的View接口,这就是博客最开始的流程图中View层不能和Model层直接建立联系的具体代码实现,当Presenter实现类的 mView.refreshViewMistakeIntruductionList(bean)被执行的时候,作为子类的MainActivity中的覆写函数会被执行,取消转圈并且重绘UI
@Override
public void refreshViewMistakeIntruductionList(LocationResponseBean bean) {
//获取到数据,取消转圈
dismiss();
//重绘text
tv_location.setText(bean.getLat()+","+bean.getLon());
}
由此,MVP的一整套流程都在这个Demo中完美的实现了,这也是我认为搭建MVP项目最简单,最方便的写法。Demo已打包上传:https://download.csdn.net/download/crystal_xing/10811027,关于MVP中所用的依赖注入框架Dagger2,会用同样的Demo再写一篇新的博客进行总结分析。