一.使用背景
1.逻辑业务被塞到View中(Activity),使得View变的混乱
2.MVP可以分离显示层和逻辑层,他们之间通过接口进行通信,降低耦合
3.数据层(可能是本地数据库检索数据,远程服务器,或者被替换)
4.UI层(随着产品迭代,肯定会重新设计),如果View中混合着逻辑,那么UI变化导致我们修改新的View控件,就要到原来的View中抽离具体的业务逻辑
理想状态:同一份逻辑代码搭配不同的显示界面,因为他们之间并不依赖于具体,而是依赖抽象
对于一个可扩展,稳定的应用来说,我们需要定义分离各个层,主要UI层,业务逻辑层(mvp中放到P)和数据层(M)
二.MVP模式的三个角色
1.Presenter---交互中间人
Presenter主要作为沟通View和Model的桥梁,他从Model层获取数据后(4),返回给View层(1),
使得View和Model之间没有耦合,也将业务逻辑从View角色上抽离出来
2.View----用户界面
View通常指的是Activity,Fragment或者某个View控件,它含有一个一个Presenter成员变量。通常View需要实现一个逻辑接口,将View上的操作转给Presenter进行实现(2),最后Presenter调用View逻辑接口将结果返回给View元素
3.Model----数据存储
对于一个结构化的App来说,Model角色主要是提供数据的存取功能,Presenter需要通过Model层存储,获取数据(3,4),简单的说,Model就是封装了数据库DAO或者网络获取数据的角色,或者两者方式都有的集合
三.MVP简单实现
//接口M
public interface ArticleModel {
public void saveArticles(List<Article> articles);
public void loadArticlesFromCache(DataListener<List<Article>> listener);
}
//具体的M
public class ArticleModeImple implements ArticleModel {
List<Article> mCacheArticles = new LinkedList<>();
@Override
public void saveArticles(List<Article> articles) {
mCacheArticles.addAll(articles);
}
@Override
public void loadArticlesFromCache(DataListener<List<Article>> listener) {
listener.onComplete(mCacheArticles);
}
}
//链接V跟P的接口
public interface ArticleViewInterface {
public void showArticles(List<Article> articles);//展示数据
public void showLoading();
public void hideLoading();
}
//具体的V
public class MainActivity extends Activity implements ArticleViewInterface {
RecyclerView mRecycleView;
ProgressBar progressBar;
List<Article> mArticles = new LinkedList<Article>();
ArticleAdapter mAdapter;
ArticlePresenter mPresenter;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//初始化控件
initViews();
//初始化请求队列
//....
//构建ArticlePresenter,与ArticleActity建立关联
mPresenter = new ArticlePresenter(this);
//请求文章数据
mPresenter.fetchArticles();
}
private void initViews() {
//省略代码
//....
}
@Override
public void showArticles(List<Article> result) {
mArticles.addAll(result);//更新数据源
mAdapter.notifyDataSetChanged();//更新UI
}
@Override
public void showLoading() {
}
@Override
public void hideLoading() {
}
}
//具体的P(一般会有一个接口P)
/**
*Presenter作为View和Model的中间人
* */
public class ArticlePresenter {
//ArticleView接口,代表了View接口角色
ArticleViewInterface mArticleView;
//文章数据的Model,也就是Model角色
ArticleModel mArticleModel = new ArticleModeImple();
//从网络上获取文章的API
ArticleAPI mAriticleApi = new ArticleAPIImpl();
public ArticlePresenter(ArticleViewInterface mArticleView) {
this.mArticleView = mArticleView;
}
//获取文章,也就是我们的业务逻辑
public void fetchArticles(){
mArticleView.showLoading();
mAriticleApi.fetchArticles(new DataListener<List<Article>>(){
@Override
public void onComplete(List<Article> result) {
//数据加载完,调用View的showArticles函数将数据传递给View显示
mArticleView.showArticles(result);
mArticleView.hideLoading();
//存储到数据库
mArticleModel.saveArticles(result);
}
});
}
public void loadArticlesFromDB(){
mArticleModel.loadArticlesFromCache(new DataListener<List<Article>>() {
@Override
public void onComplete(List<Article> result) {
//从数据库加载
mArticleView.showArticles(result);
}
});
}
}
通过这个用例可以看到,Presenter对于View是完全解耦的,
1.Presenter依赖的是ArticleViewInterface抽象,而不是具体的MainActivity这个类,因此当UI界面变化,只要新UI实现AriticleViewInterface以及相关的逻辑就可以跟Presenter用起来
2.Presenter将业务逻辑从MainActivity抽离出来,让MainActivity变得非常轻量级,MainActivity只要做一些View的初始化
3.MVP中的View和Model不能直接通信,他们交互通过Presenter,ArticlePresenter中持有
ArticleViewInterface(抽象),还持有ArticleModel(抽象),这两个的具体实现可以轻易被替换