首先定义View角色,定义一个MvpView接口代表View角色的抽象定义:
public interface MvpView{
public void onShowLoding();
public void onHideLoding();
}
然后是具体的View角色,一般而言,Activity、Fragment是需要重构的地方,首先要对这些类型定义一个功能接口:
//展示文章列表的MVP View接口
public interfiace ArticleListView extends MvpView {
public void onFetchedArticles(List<Article> result);
public void clearCacheArticles():
}
然后ArticleListFragment要实现这个接口,在这些接口中实现相应的功能,即此时ArticleListFragment扮演的是这个MvpView角色:
//显示文章列表的Fragment
public class ArticleListFragment extends Fragment implements OnRefreshListener,OnLoadListener,ArticleListView {
protected SwipeRefreshLayout mSwipeRefreshLayout;
protected AutoLoadRecyclerView mRecyclerView;
protected ArticleAdapter mAdapter;
protected ArticleListPresenter mPresenter = new ArticleListPresenter();
public void onResume(){
super.onResume();
mPresenter.attach(this);
mPresenter.fetchLastestArticles();
}
public void onRefresh() {
mPresenter.fetchLastestArticles();
}
public void onLoad() {
mPresenter.loadNextPageArticles();
}
public void onFetchedArticles(List<Article> result) {
mAdapter.addItems(result);
}
public void clearCacheArticles() {
mAdapter.clear();
}
public void onShowLoding() {
mSwipeRefreshLayout.setRefreshing(true);
}
public void onHideLoding() {
mSwipeRefershLayout.setRefreshing(false);
}
publci void onDestroy() {
super.onDestroy();
mPresenter.detach();
}
}
在上面代码中,此时Fragment非常简单,只有一些初始化视图和对视图进行一些简单的代码,相关的业务逻辑都通过ArticleListPresenter来实现。这时引入 了MVP中的另一个核心元素Presenter。Presenter是View与Model交互的中间人,我们的业务逻辑也包含在该角色中。这样就相当于Presenter要持有View对象,而我们的View对象往往是Activity、Fragment,当Activity退出时Presenter如果正在招行一个耗时的网络请求,那么将导致Activity的内存无法被释放而千万内存泄漏。因此,需要定义一个含有关联、取消关联View角色的Presenter基类:
//Presenter抽象类
public abstract class BasePresenter<T extends MvpView> {
T mView;
public void attach(T view) {
mView = view;
}
public void detach() {
mView = null;
}
}
其中T就是一个具体的MVP的View,因为每个Presenter都需要与View打交道。在初始化时通过attach关联View,在Activity或者Fragment的OnStop或onDestroy时调用detach取消关联。
然后定义ArticleListPresenter,将ArticleListFragment的业务逻辑转移到改类中:
/*
*文章列表的Presenter负责从网络上加载最新的文章列表。第一次加载最新文章列表时,先从数据库中加载缓存,然后再从网络上加载最新的数据。
*/
public class ArticleListPresenter extends BasePresenter<ArticleListView> {
public static final int FIRST_PAGE = 1;
private int mPageIndex = FIRST_PAGE;
ArticleParser mArticleParser = new ArticleParser();
private boolean isCacheLoaded = false;
public void fetchLastestArticles() {
if (!isCacheLoaded) {
mView.fetchedArticles(DatabaeHelper.getInstance().loadArticles());
}
fetchArticleAsync(FIRST_PAGE);
}
private void fetchArticleAsync(final int page) {
mView.onShowLoding();
HttpFlinger.get(prepareRequestUrl(page),mArticleParse,new DataListener<List<Article>>() {
public void onComplete(List<Article> result) {
mView.onHideLoding();
if (!isCacheLoaded && result != null) {
mView.clearCacheArticles();
isCacheLoaded = true;
}
if (result == null) {
return;
}
mView.onFetchedArticles(result);
DatabaseHelper.getInstance().saveArticles(result);
updatePageIndex(page,result);
}
});
}
}
从上述代码中可以看到网络请求、数据库操作等相关的业务逻辑都被隔离在Presenter中。ArticleListFragment等View角色只负责处理视图的显示、页面跳转等简单功能,避免了业务逻辑耦合在Activity、Fragment等View角色中,导致难以维护和修改。而Presenter则负责具体的业务逻辑处理,从数据库、网络获取资源,并且对数据、操作进行一些逻辑处理。这个MVP中目前没有真正意义上的Model,当业务比较复杂时,可以将获取数据 的操作移到一个独立的Model层,Model就是我们的数据源,而不是在Presenter中来控制这个逻辑,此时Model相当于数据中心。
网友评论