Android MVP架构模式
我们平时开发都使用的是MVC模式,也就是模型-视图-控制器,随着业务逻辑越来越复杂,Activity类一方面要负责控制View绘制,另一方面又要负责与用户交互及业务逻辑的处理,变得越来越臃肿,为了提高代码可读性降低后期维护成本我建议大家采用MVP模式进行开发,MVP全称Model-View-Presenter,MVP模式通过解耦显示层和逻辑层,避免业务逻辑被塞进View中,能够有效降低View层复杂性,同时也是符合设计模式中的单一职责原则,易于维护。
MVP流程图如图所示:
MVP的三个角色
- Presenter——交互中间人
Presenter主要作为View和Model的桥梁,它从Model层检索数据,返回给View层,使得View和Model层没有耦合,也将业务逻辑从View角色中抽离出来。 - View——用户界面
View通常是指Activity、Fragment或者某个View控件,它含有一个Presenter成员变量。通常View需要实现一个逻辑接口,将View上的操作转交给Presenter处理,最后Presenter调用View逻辑接口将结果返回给View元素。 - Model——数据的存取
对于一个结构化的App来说,Model角色主要是提供数据的存取功能。Presenter需要通过Model层存储、获取数据,Model就像一个数据仓库。更直白的说,Model是封装了数据DAO或者网络获取数据的角色。
MVC、MVP架构对比
MVC架构:
View:对应于布局文件
Model:实体模型
Controllor:对应于Activity
- View可以与Model直接交互。
- Controller是基于行为的,并且可以被多个View共享。
- 可以负责决定显示哪个View。
MVP架构:
View: 对应于Activity、Fragment,负责View的绘制以及与用户交互
Model: 实体模型
Presenter: 负责完成View于Model间的交互
- View不直接与Model交互,而是通过与Presenter交互来与Model间接交互。
- Presenter与View的交互是通过接口来进行的。
- 通常View与Presenter是一对一的,但复杂的View可能绑定多个Presenter来处理逻辑。
从MVC到MVP主要的转变就是减轻Activity的职责,将Activity中负责逻辑处理的操作提取出来放到Presenter中处理,降低Activity中代码复杂度,便于代码的可读及后期维护。
MVP架构模式实现
MVP并不是一个标准化的模式,它的实现方式有多种,只要能保证Presenter将View和Model解耦、降低类型复杂度、各模块可独立测试、独立变化即可,在Android开发中,我们一般把Activity、Fragment作为View层,View层通过接口与Presenter层交互,Presenter层作为View、Model层的桥梁,处理业务逻辑,Model层处理数据的存储与获取。
- Model层
实体模型类
public class NewsDetail {
public String detail_source;
public MediaUserBean media_user;
public int publish_time;
public String title;
public String url;
public boolean is_original;
public boolean is_pgc_article;
public String content;
public String source;
public int video_play_count;
public static class MediaUserBean {
/**
* no_display_pgc_icon : false
* avatar_url : http://p1.pstatp.com/thumb/411000674c8942528d2
* id : 6347463786
* screen_name : 发现世界
*/
public boolean no_display_pgc_icon;
public String avatar_url;
public String id;
public String screen_name;
}
}
Model层数据获取(示例)
public interface ApiService {
String GET_ARTICLE_LIST = "api/news/feed/v62/?refer=1&count=20&loc_mode=4&device_id=34960436458&iid=13136511752";
String GET_COMMENT_LIST = "article/v2/tab_comments/";
/**
* 获取新闻列表
*
* @param category 频道
* @return
*/
@GET(GET_ARTICLE_LIST)
Observable<NewsResponse> getNewsList(@Query("category") String category, @Query("min_behot_time") long lastTime, @Query("last_refresh_sub_entrance_interval") long currentTime);
/**
* 获取新闻详情
*/
@GET
Observable<ResultResponse<NewsDetail>> getNewsDetail(@Url String url);
}
- View层
View层(Activity、Fragment)直接持有Presenter对象,而Presenter通过接口间接持有View对象,View层直接调用Presenter方法处理业务逻辑,Presenter将处理结果通过回调接口的方式传递给View层。
public abstract class CMUMvpBaseActivity<T extends CMUMvpBasePresenter> extends CMUBaseActivity {
protected T mPresenter;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mPresenter = createPresenter();
provideContentViewId();
ButterKnife.bind(this);
initView();
initListener();
initData();
}
//用于创建Presenter和判断是否使用MVP模式(由子类实现)
protected abstract T createPresenter();
//得到当前界面的布局文件id(由子类实现)
protected abstract int provideContentViewId();
public void initView(){}
public void initData(){}
public void initListener(){}
@Override
protected void onDestroy() {
super.onDestroy();
if(mPresenter != null){
mPresenter.detachView();
mPresenter = null;
}
}
}
public abstract class CMUMvpBaseFragment<T extends CMUMvpBasePresenter> extends LazyLoadFragment{
protected T mPresenter;
private View rootView;
protected Activity mActivity;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mPresenter = createPresenter();
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
if (rootView == null) {
rootView = inflater.inflate(provideContentViewId(),container,false);
ButterKnife.bind(this, rootView);
initView(rootView);
initData();
initListener();
} else {
ViewGroup parent = (ViewGroup) rootView.getParent();
if (parent != null) {
parent.removeView(rootView);
}
}
return rootView;
}
/**StateView的根布局,默认是整个界面,如果需要变换可以重写此方法*/
public View getStateViewRoot() {
return rootView;
}
@Override
public void onAttach(Context context) {
super.onAttach(context);
mActivity = (Activity) context;
}
/**
* 初始化一些view
* @param rootView
*/
public void initView(View rootView) {
}
/**
* 初始化数据
*/
public void initData() {
}
/**
* 设置listener的操作
*/
public void initListener() {
}
@Override
protected void onFragmentFirstVisible() {
//当第一次可见的时候,加载数据
loadData();
}
//用于创建Presenter和判断是否使用MVP模式(由子类实现)
protected abstract T createPresenter();
//得到当前界面的布局文件id(由子类实现)
protected abstract int provideContentViewId();
//加载数据
protected abstract void loadData();
@Override
public void onDestroy() {
super.onDestroy();
if (mPresenter != null) {
mPresenter.detachView();
mPresenter = null;
}
rootView = null;
}
}
- Presenter层
Presenter是Model和View之间交互的桥梁,里面做一些业务逻辑的操作。
public class CMUMvpBasePresenter<V> {
protected V mView;
public CMUMvpBasePresenter(V view) {
attachView(view);
}
public void attachView(V view) {
mView = view;
}
public void detachView() {
mView = null;
}
}
大家平时开发时Activity、fragment分别继承以上父类即可(代码已提交到git),对于开发业务逻辑简单的模块使用MVC模式开发效率更高,只需在子类实现createPresenter方法直接返回null即可,而对于业务逻辑复杂的模块建议采用MVP模式进行开发。