百度一下MVP,网上资料一大堆,但都缺少一个循序渐进的过程,导致刚开始的时候我们看了一下,感觉很懵逼然后就没有然后了,哈哈,我准备从简单的慢慢的递增到复杂含有很多框架的架构模式类讲解,争取通过博客能让自己也更有理解深度。
如上如,这张图是MVP的核心,官方的MVP架构案例也是再这个基础上进行转化的。写demo的时候一般都不用架构的,直接写成了一个万能的Activity,获取网络数据,逻辑代码,界面显示都在Activity里面进行执行。但如果我们不是写demo,而是写一个项目,我们必须考虑很多因素,第一:项目代码清晰,首先一眼就知道整个页面都有那些功能;第二:可维护性,可测试性强,我们要新增功能可以跟着原来的列表进行有规律的添加;这样我们就需要对写的东西进行分层:
V:view层负责界面控件的显示,
P:presenter层负责逻辑功能代码、调用网络数据、本地数据封装层的编写
M:model层负责数据的访问操作,同时开放接口提供给presenter层进行调用
三层之间的交互采用接口的方式,然而功能越多就会产生更多的接口,所以我们还需要写两个契约类来分别管理P和V,P和M层交互用到的接口,如果我们想看view页面有那些功能的时候,我们只需要去看看P和V交互的契约类都有那些接口抽象方法就行了
下面我打算用一个简版的案例来讲述清楚上文的原理部分:
先看一下整体目录:
我们先看接口,base 下的接口为了抽象出所有请求的公共方法:
第一个start是我们刚进页面时,需要初始化那些数据内容可以放在里面进行实现;第二个方法setpResenter执行时才是真的把p层和view 层关联起来;然后是契约类MvpContract,主要作用时方便管理接口:
public interface MvpContract {
interface View extends BaseView<Presenter> {
void showData(String data);
}
interface Presenter extends BasePresenter {
void getData();
}
}
如上,P层接口为了获取数据,V层接口用于展示数据。最后一个接口是TaskDataSource,作用是建立其model层和presenter层之间的联系:
public interface TasksDataSource {
interface GetDataCallBack {
void onDataLoad(String result);
void onDataNotAvailable();
}
void getTasks(@NonNull String id, @NonNull GetDataCallBack callback);
}
如上,这里的getDataCallBack内部接口是为了p层调用model层的回调方法做准备的,你看下面那个getTasks方法第二个参数不就是这个接口的形参么,model层会去实现这个接口,而presenter又会通过拿到的model对象调用这个获取数据任务方法,在回调方法里面获取自己想要的数据。
上面的接口就像是m-----p------v层的粘合剂,为互相的数据通信提供了保障,下面我们三层的具体代码看到底是不是这样的,首先是activity :
/**
* crate by yy on 2018-1-17
* describle:mvp架构案例
*/
public class MainActivity extends AppCompatActivity implements MvpContract.View {
MvpContract.Presenter presenter;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
new MvpPresenter(this);
}
@Override
public void showData(String data) {
Toast.makeText(this, data, Toast.LENGTH_SHORT).show();
}
@Override
public void setPresenter(MvpContract.Presenter presenter) {
if (presenter == null) {
this.presenter = presenter;
}
}
}
这里的Activity被我看成了view层去了,我们如果需要添加另外的ui实现的时候只需要先在MvpContract.view接口增加方法,然后在view中实现接口,等待presenter层的调用时机即可,那我们再来看一看presenter呢:
public class MvpPresenter implements MvpContract.Presenter {
MvpContract.View mView;
MvpModel mvpModel;
@SuppressLint("RestrictedApi")
public MvpPresenter(@NonNull MvpContract.View mvpView) {
mView = checkNotNull(mvpView);
mvpModel = new MvpModel();
mView.setPresenter(this);
start();
}
@Override
public void getData() {
mvpModel.getTasks("001", new TasksDataSource.GetDataCallBack() {
@Override
public void onDataLoad(String result) {
mView.showData(result);
}
@Override
public void onDataNotAvailable() {
}
});
}
@Override
public void start() {
getData();
}
}
如上,我们在presenter中需要获取两个实例,一个是view层实例,一个是model层实例,view实例是我传进来的,model的实例是我new出来的,当我们有model层实例的时候就可以通过调用model层实现的方法来获取数据,里面的请求参数可以由我们自己设定,后面的回调方法就是我们上面说到的model和presenter粘合剂;在我们presenter中,我们除了可以进行网络请求,还可以进行其他的逻辑操作,写本地数据库,储存字段、开启线程或者服务等等都可以在这里实现。
最后来看看我们的model把,由于这里没有引入网络框架,只有一段测试字符,所以代码看起来非常简单:
public class MvpModel implements TasksDataSource {
@Override
public void getTasks(@NonNull String id, @NonNull GetDataCallBack callback) {
//执行数据的获取操作,从网络获取数据或者本地数据库获取数据
//retrofit+okhttp、okgo、volley 等网络框架
callback.onDataLoad("我是来自model层的数据");
}
}
其实写到这里不知道大家有没有疑问,一个简单的功能为何要写这么多代码,这不是反而增加了复杂度吗?对。是比写万能的activity麻烦多了,但代码量增多了逻辑并没有变复杂,当我们一个界面十几个接口加几个逻辑功能的时候,获取维护者想看看这个界面都有那些功能、再或者测试只想测试数据或者逻辑层的时候就方便多了。
上面这个案例是借签google官方to-do-mvp来的,要比官方案例稍微简单一些,并没有进行DI(注入)相关的代码。博客下一步我也准备来分析官方已完成的几个demo, 当然也要准备相关的基础知识:如dagger2、 Rxjava、databinding ,不然代码的理解和设计的好处读起来就会吃力很多。最后给出上面小案例的下载git地址:
https://github.com/yangyong915/MvpManager-yy