什么是MVP
MVP是一种模型,是模型(Moudle)、视图(View)、主持人(Presenter)组成的。
- 模型(Moudle):负责处理数据,比如网络的加载数据,本地存取数据。
- 视图(View)负责界面展示,及与用户交互。
- 主持人(Presenter)协调者,M与V的桥梁,负责把数据设置到
View上。
MVP模式图:
如图所示,View与Model并不直接交互,而是由Presenter实现调用Model取得数据,再把数据给View,View拿到数据在进行展示。这里概念不多讲概念。
MVP的好处:
这样分层的好处就是大大减少了Model与View层之间的耦合度。一方面可以使得View层和Model层单独开发与测试,互不依赖。另一方面Model层可以封装复用,可以极大的减少代码量。当然,MVP还有其他的一些优点,这里不再赘述。下面看下MVP模式在具体项目中的使用。
假设没有MVP,也没有MVC,现在要实现这种视图(V)和数据(M)的分离,应该怎么去做?这个时候会用到P(中间人)来负责拿取M,然后在传递给V。
V->P 在V视图里取得P的事例,调用P的方法,去获取数据。
对应代码应该这么写:
//这里已加载一个新闻为例,给P取名为NewsPresenter
NewsPresenter presenter=new NewsPresenter();
//在NewPresenter定义的加载数据的方法,里面调用Moudle,去加载数据
presenter.loadDatas();
为了让P更好的扩展,给P定义一个接口,由P去实现这个接口,
代码应该这么写:
public interface NewsPresenter {
//参数根据加载数据的需求选填
void loadDatas(int type, int pageIndex);
}
//P该这么写:
public class NewsPresenterImp implements NewsPresenter {
@Override
public void loadDatas(int type, int pageIndex) {
//这里负责调用M,去加载数据
}
}
在P中调用M去获得数据,在把数据设置到V上,应该怎么做?
代码应该这么写:
public NewsPresenterImp(NewsView newsView){
//在V 获取P的实例时,把V的实例对象传递给P
this.mView=newsView;
//M和上面的P一样,同样让它实现一个接口,这样容易扩展
mMoudle=new NewsMoudleImp();
}
定义一个M的接口,让M去实现这个接口:
public interface NewsMoudle {
//这里OnLoadListerner是一个监听返回接口
void loadNewsDatas(String url,int type,OnLoadListener onLoadListener);
}
对应NewsMoudleImp实现类:
public class NewsMoudleImp implements NewsMoudle {
@Override
public void loadNewsDatas(String url, int type, final OnLoadListener onLoadListener) {
OkHttpUtils.ResultCallback<String> callback= new OkHttpUtils.ResultCallback<String>() {
@Override
public void onSuccess(String response) {
//网络操作部分获取数据,这里可以忽略
List<NewsEntity> newsBeanList = NewsJsonUtils.readJsonNewsBeans(response, Urls.TOP_ID);
//成功调取监听成功的方法
onLoadListener.onSucceed(newsBeanList);
}
@Override
public void onFailure(Exception e) {
//失败调取监听失败的方法
onLoadListener.onFailure("加载失败");
}
};
OkHttpUtils.get(url,callback);
}
对应监听接口的:
public interface OnLoadListener {
void onSucceed( List<NewsEntity> datas);
void onFailure(String msg);
}
这个时候,在P的实现类NewsPresenterImp里的loadDatas这么写:
@Override
public void loadDatas(int type, int pageIndex) {
String url = getUrl(type, pageIndex);
mMoudle.loadNewsDatas(url, type, new OnLoadListener() {
@Override
public void onSucceed(List<NewsEntity> datas) {
mView.showData(datas); //这里mView就是V的实例引用
mView.hideProgress();
}
@Override
public void onFailure(String msg) {
mView.showFailMsg(msg);
mView.hideProgress();
}
});
}
写到这里,一个流程就走通了,首先是在V中,一般V我们都是指acitivty、Fragment,在这里new一个P的实例,让P去调用M的实例去加载数据,也就是上面的代码,M取得数据后,不管成功或着失败,都把这个结果返回交给P,最后由P去处理这个结果,把处理的结果,给V,也就是mView这个V的引用,从而实现MVP这一整套逻辑。
看V,也同样实现一个接口,这里给它取名NewsView,对应代码:
public interface NewsView {
//展示数据
void showData(List<NewsEntity> newsDatas);
//显示度条
void showProgress();
//隐藏进度条
void hideProgress();
//获取数据失败时,返回的信息
void showFailMsg(String msg);
}
V去实现这个V的接口,代码这样写:
ublic class MainActivity extends AppCompatActivity implements NewsView, SwipeRefreshLayout.OnRefreshListener {
private NewsPresenterImp presenter;
private String urlPath = "";
private List<NewsEntity> mData;
private int mType = 0;
private int pageIndex = 0;
private SwipeRefreshLayout swipeRefreshLayout;
private RecyclerView recycleView;
private NewsAdapter mAdapter = null;
private LinearLayoutManager mLayoutManager;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initView();
initDatas();
}
private void initView() {
swipeRefreshLayout = (SwipeRefreshLayout) findViewById(R.id.swiperefreshlayout);
swipeRefreshLayout.setOnRefreshListener(this);
recycleView = (RecyclerView) findViewById(R.id.recyclerview);
recycleView.setHasFixedSize(true);
mLayoutManager = new LinearLayoutManager(this);
recycleView.setLayoutManager(mLayoutManager);
recycleView.setItemAnimator(new DefaultItemAnimator());
mAdapter = new NewsAdapter(this);
}
private void initDatas() {
//这里重点,获取P的实例,让P去调用Moudle的实例加载数据
presenter = new NewsPresenterImp(this);
presenter.loadDatas(mType, pageIndex + Urls.PAZE_SIZE);
}
@Override
public void showData(List<NewsEntity> newsDatas) {
//数据获取成功后,在P中V的引用mView调取这个方法,得到数据
}
@Override
public void showProgress() {
//显示进度条
}
@Override
public void hideProgress() {
//隐藏进度条
}
@Override
public void showFailMsg(String msg) {
Toast.makeText(MainActivity.this, "msg", Toast.LENGTH_SHORT).show();
}
}
结论:整个逻辑就这样,仔仔细细看几遍,动手敲敲,会发现很清晰,就到这里了,代码例子时参考下面的例子写的,有问题就拍砖,欢迎多多指教~~