在讲MVP 之前,我们先来简单说下什么是MVC, 即Model(模型)、View(视图)、Control(控制器),相信大家对于MVC模式早已耳熟能详。原理性的东西这里不再多说。MVC在AndroidApp里面就有很好的体现。因为对于Android本身来说,界面部分的开发一般会用XML文件进行界面的描述开发。也就是MVC中的View层。而对于Model部分则大多是对应本地数据文件的读取或从网络获取数据。最后的Control控制器则有Activity来担当。MVC就说到这里,相信大多数Android猿们也是基于这种模式进行开发的。接下来,我们就来谈一谈今天的主角MVP模式在Android中又是如何实现的。

何为MVP呢?即Model,VIew,Presenter(交互中间人相当于Control) 。但这里的Presenter隔离了Model和View之间的通信,使得Model和View之间能够完全解耦。在传统的MVC中,Activity担当了Control的角色,同时还要负责Dialog,Toast,PopupWindow的弹出,这就往往让Activity的责任变得繁重。一个Activity可能动不动就是几千行代码。而在MVP中View的角色不仅仅只是XML,而变成了Activity,Activity只负责View的工作。结合上面说的MVP能使Model和View之间能完全解耦,也就是说,在Activity中不会有任何关于Model层的操作,这就符合面向对象设计原则中的单一职责,让各个模块只负责自己的部分。更易于维护,代码也会更加简介。下面我会以一个小的项目来演示MVP在Android中如何使用。我在今日头天的web页拿到了一个新闻的URL,获取Json数据,解析显示

Bean

package himan.mvp.bean;import java.io.Serializable;public class NewsInfo implements Serializable {/** *  */private static final long serialVersionUID = 1L;private String datetime;private int id;private String title;private String imageUrl;private String abstractInfo;public String getDatetime() {return datetime;}public void setDatetime(String datetime) {this.datetime = datetime;}public int getId() {return id;}public void setId(int id) {this.id = id;}public String getTitle() {return title;}public void setTitle(String title) {this.title = title;}public String getImageUrl() {return imageUrl;}public void setImageUrl(String imageUrl) {this.imageUrl = imageUrl;}public String getAbstractInfo() {return abstractInfo;}public void setAbstractInfo(String abstractInfo) {this.abstractInfo = abstractInfo;}public NewsInfo(String datetime, int id, String title, String imageUrl,String abstractInfo) {super();this.datetime = datetime;this.id = id;this.title = title;this.imageUrl = imageUrl;this.abstractInfo = abstractInfo;}public NewsInfo() {}}

Model层的接口:还记得前两篇帖子讲的面向对象的六大设计模式精髓:面向接口编程,依赖于抽象

package himan.mvp.model;import himan.mvp.bean.NewsInfo;import java.util.List;public interface INewsModel {/** * 加载数据 *  * @param dataListener */void loadNews(IOnDataListener<List<NewsInfo>> dataListener);/** * 缓存数据 *  * @param listNews */void saveNews(List<NewsInfo> listNews);}

Model实现类

package himan.mvp.modelimpl;import java.util.List;import himan.mvp.bean.NewsInfo;import himan.mvp.model.INewsModel;import himan.mvp.model.IOnDataListener;import himan.mvp.net.NewsNetHelper;import himan.mvp.net.volley.UIDataListener;public class NewsModelImpl implements INewsModel {@Overridepublic void loadNews(final IOnDataListener<List<NewsInfo>> dataListener) {  // 回调接口NewsNetHelper netHelper = new NewsNetHelper();netHelper.setDataListener(new UIDataListener<List<NewsInfo>>() {@Overridepublic void onDataChanged(List<NewsInfo> data) {if (data == null) {dataListener.error();} else {dataListener.completeLoad(data);}}});netHelper.doHttpGet("http://toutiao.com/api/article/recent/?source=2&count=20&category=__all__&max_behot_time=1449467901.41&utm_source=toutiao&offset=0&_=1449468004256");}@Overridepublic void saveNews(List<NewsInfo> listNews) {// 缓存数据到本地}}

View层接口:依赖于抽象编程

package himan.mvp.view;import himan.mvp.bean.NewsInfo;import java.util.List;public interface INewsView {/** * 显示新闻列表 *  * @param listNews */public void showNewsList(List<NewsInfo> listNews);/** * 显示正在加载中进度条 */public void showLoading();/** * 关闭正在加载中进度条 */public void hideLoading();/** * 显示数据加载失败 */public void showError();}

MVP关键之处:中间人Presenter

package himan.mvp.presenter;import java.util.List;import himan.mvp.bean.NewsInfo;import himan.mvp.model.INewsModel;import himan.mvp.model.IOnDataListener;import himan.mvp.modelimpl.NewsModelImpl;import himan.mvp.view.INewsView;public class NewsPresenter {         // 同时持有Model层和View层的引用private INewsView mNewsView;private INewsModel mNewsModel = new NewsModelImpl();public NewsPresenter(INewsView newsView) {this.mNewsView = newsView;}public void showNews() {mNewsView.showLoading();mNewsModel.loadNews(new IOnDataListener<List<NewsInfo>>() {@Overridepublic void error() {// 加载失败mNewsView.hideLoading();mNewsView.showError();}@Overridepublic void completeLoad(List<NewsInfo> t) {mNewsView.hideLoading();mNewsView.showNewsList(t);}});}}

Activity实现了View接口

package himan.mvp;import himan.mvp.adapter.NewsAdapter;import himan.mvp.bean.NewsInfo;import himan.mvp.net.volley.VolleyQueueController;import himan.mvp.presenter.NewsPresenter;import himan.mvp.utils.LoadingWindow;import himan.mvp.view.INewsView;import java.util.ArrayList;import java.util.List;import android.app.Activity;import android.os.Bundle;import android.widget.ListView;import android.widget.Toast;import com.nostra13.universalimageloader.core.ImageLoader;import com.nostra13.universalimageloader.core.ImageLoaderConfiguration;/** * 测试 加载的数据 是从今日头条官网的直接push下来的 *  * @author Mr.Himan *  */public class MainActivity extends Activity implements INewsView {private ListView mlVNews;private NewsAdapter mNewsAdapter;private List<NewsInfo> mListNews;private NewsPresenter mNewsPresenter;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);// 初始化Volley框架VolleyQueueController.init(this);// ImageLoader 默认配置参数ImageLoaderConfiguration configuration = ImageLoaderConfiguration.createDefault(this);// 初始化ImageLoaderImageLoader.getInstance().init(configuration);initView();mNewsPresenter = new NewsPresenter(this);mNewsPresenter.showNews();}private void initView() {mlVNews = (ListView) findViewById(R.id.news_lv_news_list);mListNews = new ArrayList<NewsInfo>();mNewsAdapter = new NewsAdapter(this, mListNews, R.layout.lv_item_news);mlVNews.setAdapter(mNewsAdapter);}@Overridepublic void showNewsList(List<NewsInfo> listNews) {mListNews.addAll(listNews);mNewsAdapter.notifyDataSetChanged();}@Overridepublic void showLoading() {Toast.makeText(this, "正在加载数据...", Toast.LENGTH_LONG).show();}@Overridepublic void hideLoading() {Toast.makeText(this, "数据加载成功", Toast.LENGTH_SHORT).show();}@Overridepublic void showError() {}}

这就是MVP实现一个新闻展示的全部代码(貌似头条的接口关掉了 - -),Activity实现了View接口,而Presenter中保存有View和Model层的引用,使得Presenter能通过Model拿到数据,通过View的引用控制视图的显示。流程大概是这样,Presenter先通过Model的引用拿到数据,然后通过View的引用进行数据的显示,视图更新。Activity中的代码也非常简介。通过上面代码我们能够看出MVP的优点还是很多的,首先使得Model和View层完全解耦,我们知道项目中改动最多的一般都是View层,这就让程序易于维护,而且能够高度复用Presenter,而且也易于后期的拓展。缺点也显而易见,就是爆炸式增长的类和接口。复用的时候也可能造成接口的冗余。最大的问题是Presenter持有着View的强应用,在请求网络数据等耗时操作的时候,Activity可能被销毁,可能会导致View无法回收,而造成内存问题。关于这个问题,我会在下一篇MVP的帖子中讲解如何处理,欢迎关注






更多相关文章

  1. “罗永浩抖音首秀”销售数据的可视化大屏是怎么做出来的呢?
  2. Nginx系列教程(三)| 一文带你读懂Nginx的负载均衡
  3. 不吹不黑!GitHub 上帮助人们学习编码的 12 个资源,错过血亏...
  4. Android(安卓)实现布局动态加载
  5. Android中activity和xml的第一个项目
  6. 基于JSON RPC的一种Android跨进程调用解决方案了解一下?
  7. Android(安卓)Glide图片加载库基础使用详解
  8. android 获取本地缓存文件大小,删除功能
  9. 解剖Android联系人之一,基于2.1

随机推荐

  1. android里getView,inflate,listview问题
  2. android上多样式文本的使用
  3. Android积木之图片的生成和保存
  4. 从源码一次彻底理解Android的消息机制
  5. cocos2d-x 移植安卓错误解决
  6. Android(安卓)sdk更新代理配置
  7. android定时器
  8. android实现退出时关闭所有activity
  9. Delphi XE5 Android(安卓)调用手机震动
  10. android 获取当前时间