安卓开发框架(MVP+主流框架+基类+工具类)--- MVP模式

来源:互联网 发布:黑马程序员课程表 编辑:程序博客网 时间:2024/05/16 14:37

学习/参考地址:
http://www.jianshu.com/p/9d40b298eca9
http://blog.csdn.net/lmj623565791/article/details/46596109

前言

MVP开发模式将代码整体划分为数据处理M、页面展示V、业务逻辑P三个模块,分工明确,各尽其职。

可降低代码耦合度,提高代码的结构清晰度、可读性、维护性和复用性等,但相应地会增加文件的数量。


简介

下面通过 “正经版” 和 “餐厅版” 来阐述M、V、P三者的职责。

“正经”版

M层(model):数据模型/处理层。负责数据处理、数据提供,如网络请求,数据库操作
V层(view):视图展示层。负责界面展示,如Activity,Fragment
P层(presenter):业务逻辑层。负责业务逻辑服务,是V层与M层间的桥梁

MVP示意图1

举个例子
请求正在上映的电影数据,然后展示到页面:
1. V层(activity、fragment或其他)告诉P层“我要正在上映的电影数据”
2. P层通知M层,“V层要正在上映的电影数据,你去获取下,有结果了告诉我”
3. M层开启网络请求获取数据,结果返回后则通知P层(请求可能成功也可能失败)
4. P层再将结果反馈给V层(一般通过接口进行回调,尤其是耗时操作),最后再由V层进行展示

“餐厅”版

(个人YY,比喻可能不当,仅供参考帮助理解)

M层(model):厨师。负责做菜
V层(view):顾客。点餐吃饭
P层(presenter):服务员。提供下单、上菜等各种服务

MVP示意图2

举个例子
顾客到了餐厅想吃一份铁板牛扒:
1. 顾客(V层)告诉服务员(P层)“我要一份铁板牛扒”
2. 服务员(P层)下单后通知厨师(M层),“有个顾客点了一份铁板牛扒,辛苦你了,做好后告诉我”
3. 厨师(M层)开始大展厨艺,完成铁板牛扒后通知服务员(P层)上菜 【当然也有可能没食材做不了,让服务员告知顾客换其他菜式,好比网络请求也有失败的情况】
4. 服务员(P层)将铁板牛扒端给顾客(V层),最后顾客(V层)就可以用餐了

如果不使用开发模式而把代码都写到一块的话,就会显得冗杂和混乱,也不便日后排查问题与维护。
就像你去餐馆吃饭,厨师直接在你身旁切菜剁肉下厨,这样顾客的用餐环境肯定不够优雅


应用

了解完MVP三者的职责后,下面按照“正经”版中的例子(请求正在上映的电影数据,然后展示到页面),用代码片段来演示在项目中的应用。

  • View层(activity、fragment或其他)告诉P层“我要正在上映的电影数据”
//View层public class MovieActivity implements IMovieView{  ....  MoviePresenter mMoviePresenter;   @Override     public void onCreate(Bundle savedInstanceState) {           mMoviePresenter = new MoviePresenter(this);//构造方法的参数为IView接口         mMoviePresenter.getPlayingMovie(10);   }   ....}
  • Presenter层通知Model层,“View层要正在上映的电影数据,你去获取下,有结果了告诉我”
//Presenter层public class MoviePresenter {    private IMovieView mIView;    public MoviePresenter(IMovieView iMovieView) {        mIView = iMovieView    }    //获取正在上映的电影    public void getPlayingMovie(int count) {        //通知M层开启请求        MovieModel.getInstance.getPlayingMovie(count, ...);    }    ....}
  • Model层开启网络请求获取数据,结果返回后则通知Presenter层(请求可能成功也可能失败)
//Model层public class MovieModel {    ...    //开启网络请求获取正在上映的电影    public void getPlayingMovie(int count, HttpObserver<List<MovieRes>>  observer,                                       PublishSubject<LifeCycleEvent> lifecycleSubject) {        //开启网络请求,结果返回后通过传入的observer回调给P层        Observable observable = RetrofitUtil.getApiService().getPlayingMovie(count);        RetrofitUtil.composeToSubscribe(observable, observer, lifecycleSubject);    }}
  • Presenter层再将结果反馈给View层(一般通过接口IView进行回调,尤其是耗时操作),最后再由View层进行展示
//Presenter层public class MoviePresenter {    ....    //获取正在上映的电影    public void getPlayingMovie(int count) {        //通知M层开启请求        MovieModel.getInstance.getPlayingMovie(count, new HttpObserver<List<MovieRes>>() {            @Override            public void onNext(String title, List<MovieRes> list) {                //通过接口IView将成功的结果回调给V层                if (mIView != null) {                    mIView.getMovieSuccess(list);                }            }            @Override            public void onError(int errType, String errMessage) {                //通过接口将失败的结果回调给V层                if (mIView != null) {                    mIView.getMovieFail(errType, errMessage);                }            }        });    }    ....}
//IView接口代码,用于Presenter层与View层的交互public interface IMovieView extends IBaseView {    //成功获取电影数据    void getMovieSuccess(List<MovieRes> list);    //获取电影数据失败    void getMovieFail(int status, String desc);}
//View层(实现回调接口IMovieView中的方法)public class MovieActivity implements IMovieView{   ...    //网络请求成功的回调    @Override    public void getMovieSuccess(List<MovieRes> list) {        if (CollectionUtil.isEmpty(list)) {            //数据为空则设置页面为“无数据”状态            getLoadLayout().setLayoutState(State.NO_DATA);        }else{            //设置页面为“成功”状态,显示正文布局            getLoadLayout().setLayoutState(State.SUCCESS);            //列表展示数据            mMovieAdapter = new MovieAdapter(mActivity, list, this);            mRvMovie.setLayoutManager(new LinearLayoutManager(getContext()));            mRvMovie.setHasFixedSize(false);            mRvMovie.setAdapter(mMovieAdapter);        }    }    //网络请求失败的回调    @Override    public void getMovieFail(int status, String desc) {        //设置页面为“失败”状态        getLoadLayout().setLayoutState(State.FAILED);    }   ...}

*注意
如果Presenter层持有了View层的引用,那么记得在V层销毁时,把Presenter层中对View层的引用置null,避免View层回收失败导致内存泄漏。

//View层public class MovieActivity implements IMovieView{    ...    @Override    public void onDestroy() {        super.onDestroy();        //销毁,避免内存泄漏        if (mMoviePresenter != null) {            mMoviePresenter.destroy();        }    }}
//Presenter层public class MoviePresenter {    ...    public void destroy() {        mIView = null;    }    ...}

其他

  1. 与MVC模式的区别:
    MVC中,V层与M层是可以互通的,而在MVP中V层与M层是不通的。
    按餐厅版来说就是,MVC中顾客可以直接告诉厨师要吃什么菜,厨师做好后直接把菜端到你面前,而MVP中只能通过服务员来完成点餐到用餐的过程。
  2. MVVM模式:
    MVVM与MVP也挺相似的,但它采用了双向绑定:View的变动,会自动反映在ViewModel,反之亦然。由于我还没实际运用过该模式,所以就不多加说明了,有兴趣的可以自行了解。

详细代码请看demo,地址:https://github.com/LJYcoder/DevBase
demo的内容流程,请看《安卓开发框架(MVP+主流框架+基类+工具类)— 开篇》

阅读全文
1 0
原创粉丝点击