安卓开发框架(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层间的桥梁
举个例子
请求正在上映的电影数据,然后展示到页面:
1. V层(activity、fragment或其他)告诉P层“我要正在上映的电影数据”
2. P层通知M层,“V层要正在上映的电影数据,你去获取下,有结果了告诉我”
3. M层开启网络请求获取数据,结果返回后则通知P层(请求可能成功也可能失败)
4. P层再将结果反馈给V层(一般通过接口进行回调,尤其是耗时操作),最后再由V层进行展示
“餐厅”版
(个人YY,比喻可能不当,仅供参考帮助理解)
M层(model):厨师。负责做菜
V层(view):顾客。点餐吃饭
P层(presenter):服务员。提供下单、上菜等各种服务
举个例子
顾客到了餐厅想吃一份铁板牛扒:
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; } ...}
其他
- 与MVC模式的区别:
MVC中,V层与M层是可以互通的,而在MVP中V层与M层是不通的。
按餐厅版来说就是,MVC中顾客可以直接告诉厨师要吃什么菜,厨师做好后直接把菜端到你面前,而MVP中只能通过服务员来完成点餐到用餐的过程。 - MVVM模式:
MVVM与MVP也挺相似的,但它采用了双向绑定:View的变动,会自动反映在ViewModel,反之亦然。由于我还没实际运用过该模式,所以就不多加说明了,有兴趣的可以自行了解。
详细代码请看demo,地址:https://github.com/LJYcoder/DevBase
demo的内容流程,请看《安卓开发框架(MVP+主流框架+基类+工具类)— 开篇》
- 安卓开发框架(MVP+主流框架+基类+工具类)--- MVP模式
- 安卓开发框架(MVP+主流框架+基类+工具类)--- 工具类
- 安卓开发框架(MVP+主流框架+基类+工具类)--- 基类
- 安卓开发框架(MVP+主流框架+基类+工具类)--- 开篇
- 安卓开发框架(MVP+主流框架+基类+工具类)--- Retrofit+RxJava
- 安卓开发框架(MVP+主流框架+基类+工具类)--- GreenDAO
- 安卓开发框架(MVP+主流框架+基类+工具类)--- Fresco
- 安卓开发框架(MVP+主流框架+基类+工具类)--- EventBus
- 安卓开发框架(MVP+主流框架+基类+工具类)--- ButterKnife
- 浅谈安卓框架mvp
- MVP安卓开发模式
- 框架模式MVP在安卓中的实践
- 开发模式——MVP框架开发
- 框架模式-MVP
- 安卓MVC vs MVP 框架
- Android开发之浅谈框架模式MVP
- MVP快速开发框架
- 简述安卓框架发展史二(mvp,mvvm)
- linux文件与目录的操作处理
- 微信支付
- Web 前端如何播放 HLS(.m3u8) 视频
- 多线程中两个必要的开销:线程的创建、上下文切换 上下文切换
- MNIST-NameError: name ‘input_data’ is not defined解决办法
- 安卓开发框架(MVP+主流框架+基类+工具类)--- MVP模式
- python网络编程学习笔记(1)--网络编程背景
- 连接MySQL数据库时出现1045和1130错误
- kd树的实现(python)
- 关联表
- 完形填空
- 块级元素上下 或 水平居中
- 采用延迟初始化来降低初始化类和创建对象的开销
- 注意当cin.getline、和cin 合用的时候