MVP模式在Android中的使用
来源:互联网 发布:手机淘宝苹果版本下载 编辑:程序博客网 时间:2024/05/16 09:25
转自:http://blog.csdn.net/feiduclear_up/article/details/46374653 废墟的树
前一篇文章中学习了MVC框架模式在Android中的使用,不了解什么是MVC框架模式的亲戳这里框架模式 MVC 在Android中的使用。其实谷歌Android开发团队是鼓励开发者利用MVC框架模式开发项目的,我们平时写代码也或多或少的在使用MVC框架模式开发项目,比如说谷歌自己退出来的Volley网络请求框架就是遵循MVC框架的。我们可以理解为Volley框架是MVC当中的模型,也就是网络数据处理这一块,无需跟View视图有任何关联。也符合视图和模型分离。可能你会觉得MVC框架已经很好用了,也能满足任何项目开发,不错,可是从上一篇博客你会发现,Controller控制器和View视图显示是在一个类Activity中体现出来的,而Android中Activity是担当Controller控制器的角色的,如果界面操作方式繁琐,视图显示复杂,那么我们不得不在Activity中添加更多的View视图显示操作,这样自然增加了Activity的代码量,也导致了Activity承担的任务和逻辑处理太多,职责不清晰。这一篇我们来介绍另外一种框架模式MVP。
MVP
MPV 是从经典的MVC模式演变过来的,其基本思路都是相通的。其中M是model模型,提供业务数据;P和MVC中的C担当的角色相似,是Presenter控制者,进行逻辑处理。V是View视图,显示数据。MVP与MVC有着一个重大的区别:在MVP中View并不直接使用Model,它们之间的通信是通过Presenter (MVC中的Controller)来进行的,所有的交互都发生在Presenter内部,而在MVC中View会从直接Model中读取数据而不是通过 Controller。
MVC框架图
MVP框架图
从上面的框架图可以看出MVC和MVP最大的区别就是 Model和View之间的关系。在MVC框架中,View是可以直接读取Model模型中的数据的,Model模型数据发生改变是会通知View数据显示发生相应的改变。而在MVP中Model和View之间的没有任何联系,是两个完全独立的模块,当Model模型发生数据改变时,通过Presenter通知View视图发生相应的UI改变。因此,个人觉得:MVP才是正真的视图和模型完全分离,也就是Model模型进行业务数据处理和View视图显示没有任何关联。
MVP for Android
在Andorid项目中,我们习惯将Activity作为MVC中的控制者来达到Model模型和View视图分离,但是在MVP框架模式中,通常将Activity作为View视图层,因为在MVC框架模式中Activity和View视图显示关联紧密,Activity中包含大量的View视图显示代码,如果哪天老板说需要修改View视图显示,这时候你是不是感觉需要修改Activity中的大量代码?这么一来会将Activity中控制逻辑破坏,也导致Activity中承担太多的职责。根据单一职责原则,Activity主要起到用户交互作用,也就是接收用户输入,显示请求结果。因此可以通过MVP框架模式来减轻Activity的职责。看看Android项目中怎么实现吧!
同样拿上一篇的天气预报小项目来举例子:
Model模型
和MVC框架模式一样,Model模型处理数据代码不变
<code class="hljs java has-numbering"><span class="hljs-javadoc">/** * Created by xjp 2015-6-7 * 天气Model接口 */</span><span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">interface</span> <span class="hljs-title">WeatherModel</span> {</span> <span class="hljs-keyword">void</span> loadWeather(String cityNO, OnWeatherListener listener);}.........<span class="hljs-javadoc">/** * Created by xjp on 2015/6/7. * 天气Model实现 */</span><span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">WeatherModelImpl</span> <span class="hljs-keyword">implements</span> <span class="hljs-title">WeatherModel</span> {</span> <span class="hljs-annotation">@Override</span> <span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">loadWeather</span>(String cityNO, <span class="hljs-keyword">final</span> OnWeatherListener listener) { <span class="hljs-comment">/*数据层操作*/</span> VolleyRequest.newInstance().newGsonRequest(<span class="hljs-string">"http://www.weather.com.cn/data/sk/"</span> + cityNO + <span class="hljs-string">".html"</span>, Weather.class, <span class="hljs-keyword">new</span> Response.Listener<Weather>() { <span class="hljs-annotation">@Override</span> <span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">onResponse</span>(Weather weather) { <span class="hljs-keyword">if</span> (weather != <span class="hljs-keyword">null</span>) { listener.onSuccess(weather); } <span class="hljs-keyword">else</span> { listener.onError(); } } }, <span class="hljs-keyword">new</span> Response.ErrorListener() { <span class="hljs-annotation">@Override</span> <span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">onErrorResponse</span>(VolleyError error) { listener.onError(); } }); }}</code>
通过OnWeatherListener接口回调将Model模型处理的数据返回给Presenter控制者。
Presenter控制器
<code class="hljs java has-numbering"><span class="hljs-javadoc">/** * Created by xjp on 2015/6/7. * 天气 Presenter接口 */</span><span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">interface</span> <span class="hljs-title">WeatherPresenter</span> {</span> <span class="hljs-javadoc">/** * 获取天气的逻辑 */</span> <span class="hljs-keyword">void</span> getWeather(String cityNO);}..........<span class="hljs-javadoc">/** * Created by xjp on 2015/6/7. * 在Presenter层实现,给Model层回调,更改View层的状态,确保Model层不直接操作View层 */</span><span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">interface</span> <span class="hljs-title">OnWeatherListener</span> {</span> <span class="hljs-javadoc">/** * 成功时回调 * *<span class="hljs-javadoctag"> @param</span> weather */</span> <span class="hljs-keyword">void</span> onSuccess(Weather weather); <span class="hljs-javadoc">/** * 失败时回调,简单处理,没做什么 */</span> <span class="hljs-keyword">void</span> onError();}.........<span class="hljs-keyword">package</span> org.rocko.demos.mvp.presenter.impl;<span class="hljs-keyword">import</span> org.rocko.demos.mvp.model.WeatherModel;<span class="hljs-keyword">import</span> org.rocko.demos.mvp.model.entity.Weather;<span class="hljs-keyword">import</span> org.rocko.demos.mvp.model.impl.WeatherModelImpl;<span class="hljs-keyword">import</span> org.rocko.demos.mvp.presenter.OnWeatherListener;<span class="hljs-keyword">import</span> org.rocko.demos.mvp.presenter.WeatherPresenter;<span class="hljs-keyword">import</span> org.rocko.demos.mvp.ui.view.WeatherView;<span class="hljs-javadoc">/** * Created by xjp on 2015/6/7. * 天气 Presenter实现 */</span><span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">WeatherPresenterImpl</span> <span class="hljs-keyword">implements</span> <span class="hljs-title">WeatherPresenter</span>, <span class="hljs-title">OnWeatherListener</span> {</span> <span class="hljs-comment">/*Presenter作为中间层,持有View和Model的引用*/</span> <span class="hljs-keyword">private</span> WeatherView weatherView; <span class="hljs-keyword">private</span> WeatherModel weatherModel; <span class="hljs-keyword">public</span> <span class="hljs-title">WeatherPresenterImpl</span>(WeatherView weatherView) { <span class="hljs-keyword">this</span>.weatherView = weatherView; weatherModel = <span class="hljs-keyword">new</span> WeatherModelImpl(); } <span class="hljs-annotation">@Override</span> <span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">getWeather</span>(String cityNO) { weatherView.showLoading(); weatherModel.loadWeather(cityNO, <span class="hljs-keyword">this</span>); } <span class="hljs-annotation">@Override</span> <span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">onSuccess</span>(Weather weather) { weatherView.hideLoading(); weatherView.setWeatherInfo(weather); } <span class="hljs-annotation">@Override</span> <span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">onError</span>() { weatherView.hideLoading(); weatherView.showError(); }}</code>
从代码中我们可以看到Presenter控制器同时持有 WeatherModel和WeatherView对象且实现了OnWeatherListener接口取回Model模型数据,因此,WeatherPresenterImpl向WeatherModel发送数据请求,然后通过OnWeatherListener接口实现获取请求结果,在将结果通过接口WeatherView把数据显示到Activity担当的View视图中。从而达到彻底将Model和View完全分离,试想在这种情况下,如果你需要修改Model是完全不会影响View视图代码的修改的,同理,修改View视图层的时候,也完全无需修改Model层。相当于Model和View互相不知道对方的存在,都是通过中间控制器Presenter来传达通信。
View视图
先定义一个View视图显示的接口WeatherView
<code class="hljs java has-numbering"><span class="hljs-javadoc">/** * Created by xjp on 2015/6/7. */</span><span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">interface</span> <span class="hljs-title">WeatherView</span> {</span> <span class="hljs-keyword">void</span> showLoading(); <span class="hljs-keyword">void</span> hideLoading(); <span class="hljs-keyword">void</span> showError(); <span class="hljs-keyword">void</span> setWeatherInfo(Weather weather);}</code>
然后实现Activity实现WeatherView接口
<code class="hljs java has-numbering"><span class="hljs-javadoc">/** * 天气界面 */</span><span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">WeatherActivity</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">BaseActivity</span> <span class="hljs-keyword">implements</span> <span class="hljs-title">WeatherView</span>, <span class="hljs-title">View</span>.<span class="hljs-title">OnClickListener</span> {</span> <span class="hljs-keyword">private</span> Dialog loadingDialog; <span class="hljs-keyword">private</span> EditText cityNOInput; <span class="hljs-keyword">private</span> TextView city; <span class="hljs-keyword">private</span> TextView cityNO; <span class="hljs-keyword">private</span> TextView temp; <span class="hljs-keyword">private</span> TextView wd; <span class="hljs-keyword">private</span> TextView ws; <span class="hljs-keyword">private</span> TextView sd; <span class="hljs-keyword">private</span> TextView wse; <span class="hljs-keyword">private</span> TextView time; <span class="hljs-keyword">private</span> TextView njd; <span class="hljs-keyword">private</span> WeatherPresenter weatherPresenter; <span class="hljs-annotation">@Override</span> <span class="hljs-keyword">protected</span> <span class="hljs-keyword">void</span> <span class="hljs-title">onCreate</span>(Bundle savedInstanceState) { <span class="hljs-keyword">super</span>.onCreate(savedInstanceState); setContentView(R.layout.activity_main); init(); } <span class="hljs-keyword">private</span> <span class="hljs-keyword">void</span> <span class="hljs-title">init</span>() { cityNOInput = findView(R.id.et_city_no); city = findView(R.id.tv_city); cityNO = findView(R.id.tv_city_no); temp = findView(R.id.tv_temp); wd = findView(R.id.tv_WD); ws = findView(R.id.tv_WS); sd = findView(R.id.tv_SD); wse = findView(R.id.tv_WSE); time = findView(R.id.tv_time); njd = findView(R.id.tv_njd); findView(R.id.btn_go).setOnClickListener(<span class="hljs-keyword">this</span>); weatherPresenter = <span class="hljs-keyword">new</span> WeatherPresenterImpl(<span class="hljs-keyword">this</span>); <span class="hljs-comment">//传入WeatherView</span> loadingDialog = <span class="hljs-keyword">new</span> ProgressDialog(<span class="hljs-keyword">this</span>); loadingDialog.setTitle(<span class="hljs-string">"加载天气中..."</span>); } <span class="hljs-annotation">@Override</span> <span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">onClick</span>(View v) { <span class="hljs-keyword">switch</span> (v.getId()) { <span class="hljs-keyword">case</span> R.id.btn_go: weatherPresenter.getWeather(cityNOInput.getText().toString().trim()); <span class="hljs-keyword">break</span>; } } <span class="hljs-annotation">@Override</span> <span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">showLoading</span>() { loadingDialog.show(); } <span class="hljs-annotation">@Override</span> <span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">hideLoading</span>() { loadingDialog.dismiss(); } <span class="hljs-annotation">@Override</span> <span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">showError</span>() { <span class="hljs-comment">//Do something</span> Toast.makeText(getApplicationContext(), <span class="hljs-string">"error"</span>, Toast.LENGTH_SHORT).show(); } <span class="hljs-annotation">@Override</span> <span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">setWeatherInfo</span>(Weather weather) { WeatherInfo info = weather.getWeatherinfo(); city.setText(info.getCity()); cityNO.setText(info.getCityid()); temp.setText(info.getTemp()); wd.setText(info.getWD()); ws.setText(info.getWS()); sd.setText(info.getSD()); wse.setText(info.getWS()); time.setText(info.getTemp()); njd.setText(info.getNjd()); }}</code>
因此,Activity及从MVC中的Controller中解放出来了,这会Activity主要做显示View的作用和用户交互。每个Activity可以根据自己显示View的不同实现View视图接口WeatherView。
总结
- MVP框架模式完全将Model模型和View视图分离,从而使得代码的耦合性第,利用MVP框架写项目达到解耦作用。
- MVP和MVC最大的区别是:MVC中的V可以从M中获取数据,而MVP中M和V完全分离,互相不知道对方的存在,Presenter通过接口通信方式将V和M通信。
- 在Android中MVP框架 Activity担当View视图层和MVC框架模式不一样Activity担当控制器。
源码地址下载:源码地址
- MVP模式在Android中的使用
- 框架模式MVP在Android中的使用
- 框架模式MVP在Android中的使用
- MVP模式在Android中的使用
- MVP 模式在 Android 中的使用
- 框架模式MVP在Android中的使用
- MVP模式在Android项目中的使用
- MVP模式在Android中的使用
- MVP模式在Android项目中的使用
- MVP模式在Android项目中的使用
- MVP模式在Android项目中的使用
- MVP模式在Android项目中的使用
- MVP模式在Android项目中的使用
- MVP模式在Android中的使用
- MVP模式在Android项目中的使用
- MVP 模式在Android中的使用
- 框架模式MVP在Android中的使用
- MVP模式在Android项目中的使用
- cannot use LOB locators selected from remote tables
- javascrip将对象转换成json字符串
- netty 私有协议开发
- Eclipse上Hadoop开发环境搭建
- 【Java】抽象类和接口
- MVP模式在Android中的使用
- 一些前端开发实用的函数—1(jquery)
- 2016年中国电子信息百强企业出炉:华为居首
- NodeJS学习系列课程笔记(NodeJs 快速上手+用法示例)
- springmvc+mybatis 配置
- mysql查询条件的执行顺序
- mysql function
- 【Hibernate】多对多(双向)
- 哥德巴赫猜想(升级版)