Android中的MVP模式使用
在讲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的帖子中讲解如何处理,欢迎关注
更多相关文章
- “罗永浩抖音首秀”销售数据的可视化大屏是怎么做出来的呢?
- Nginx系列教程(三)| 一文带你读懂Nginx的负载均衡
- 不吹不黑!GitHub 上帮助人们学习编码的 12 个资源,错过血亏...
- Android(安卓)实现布局动态加载
- Android中activity和xml的第一个项目
- 基于JSON RPC的一种Android跨进程调用解决方案了解一下?
- Android(安卓)Glide图片加载库基础使用详解
- android 获取本地缓存文件大小,删除功能
- 解剖Android联系人之一,基于2.1