智能厨房重构-MVP架构
上一篇博客智能厨房-项目分包,我们介绍了项目分包的结构,这一篇我们重点来介绍一下MVP架构在项目中的应用,MVP可以说是MVC模式的一种升级,在MVP出现之前,一般都是用MVC,但是使用MVC有一个很大的缺点就是:通常将Activity作为Controller,xml文件当做View,Model数据请求类不变,但是Activity作为展示界面,通常要处理点击事件的响应,这就将C和V耦合在了一起,造成的后果就是activity动不动就大篇幅的代码,后期难以维护和升级。自从用了MVP之后,妈妈再也不要担心我的Activity类爆炸了。
1.MVP的简单介绍
View:是视图,用户界面,一般都是Activity充当这个角色,一般就是响应点击事件和加载数据到视图上。
Model:是数据处理,一般获取数据库数据、网络请求都定义在这里面。
Presenter:是组织者,是真正的执行任务的地方,一般一个presenter里面有一个View和Model的引用。
talk is cheap,让我来看一下实例。
2.MVP的实例运用
先说一下需求,假如我们现在要动态解析http://www.meishij.net/list.php?sortby=update&lm=369&page=1
美食杰往上面的数据,如何加载到我们的App上。
变成这样。
想想还是不错的,靠偷别人网上的数据就可以形成自己的数据接口了,哈哈。
先看下数据格式:
/*** 作者:GXL on 2016/8/3 0003* 博客: http://blog.csdn.net/u014316462* 作用:缩略展示美食,外部listview使用*/import java.io.Serializable;
public class FoodGeneralItem implements Serializable{/*** 标题*/private String title;/*** 链接**/private String link;/*** 图片的链接*/private String imgLink;/*** 作者名*/private String writer;public String getTaste() {return taste;}public void setTaste(String taste) {this.taste = taste;}/*** 味道*/private String taste;public String getDiscuss() {return discuss;}public void setDiscuss(String discuss) {this.discuss = discuss;}/*** 评论*/private String discuss;public String getTitle() {return title;}public String getDate() {return date;}public void setDate(String date) {this.date = date;}/*** 步骤 时间*/private String date;public void setTitle(String title) {this.title = title;}public String getLink() {return link;}public void setLink(String link) {this.link = link;}public String getImgLink() {return imgLink;}public void setImgLink(String imgLink) {this.imgLink = imgLink;}public String getWriter() {return writer;}public void setWriter(String writer) {this.writer = writer;}@Overridepublic String toString() {// TODO Auto-generated method stubreturn title;}
}
这没什么说的,就是需要展示的一些数据。我们看关键的MVP用法。先给一个类图给一个直观的认识。
下面说明一下:
View部分
通常一个功能界面对应一个View接口,接口里面定义数据加载View中方法,比如:将上面的数据集合加载到
listview中就可以定义一个接口方法,看一下IFoodFragment的实现。
/*** 作者:GXL on 2016/8/3 0003* 博客: http://blog.csdn.net/u014316462* 作用:FoodFragment的View接口*/
public interface IFoodFragment {//加载更多void onLoadMore(List list);//下拉刷新void onRefresh(List list);//初始化sliderViewvoid onInitSliderShow(List list);
}
还是很清晰的,下拉刷新的处理函数、上拉加载更多的处理函数、初始化一个SliderView函数,这是sliderView是一个类似广告位滚动的自定义View,后面会写一篇博文介绍一下。看一下IFoodFragment在FoodFragment的实现。
*** 作者:GXL on 2016/8/3 0003* 博客: http://blog.csdn.net/u014316462* 作用:展示美食的页面*/
public class FoodFragment extends Fragment implements IFoodFragment, XListView.IXListViewListener {@Bind(R.id.xListView)XListView xListView;@Bind(R.id.menu)ImageView menu;@Bind(R.id.search)EditText search;@Bind(R.id.loading)RelativeLayout loading;@Bind(R.id.tip)LinearLayout tip;private int[] mIconList = {R.drawable.cate_jiachang_5, R.drawable.cate_zhonghua_5,R.drawable.cate_xiaochi_5, R.drawable.cate_waiguo_5,R.drawable.cate_hongbei_5, R.drawable.cate_renqun_5};private String[] mNameList = {"家常菜谱", "中华菜系", "各地小吃", "外国菜谱", "烘焙", "我的收藏"};private FoodGeneralAdapter mAdapter;private LinearLayout mFoodFragmentHead;private List
关键看一下实现的三个方法理解一下。Activity中都需要一个Presenter对象,用来页面响应时真正的处理请求。
Model部分
先看一下FoodModelImpl接口的实现
/*** 作者:GXL on 2016/8/3 0003* 博客: http://blog.csdn.net/u014316462* 作用:FoodModel接口*/
public interface FoodModelImpl {/*** 获取美食的大概信息* @param sortby* @param type* @param page* @param listener*/void getGeneralFoodsItem(String sortby,int type,int page,BaseListener listener);/*** 获取美食的详细做法* @param foodlink* @param listener*/void getFoodDetailTeachItem(String foodlink,BaseListener listener);/*** 获取滚动展示的数据集合* @param listener*/void getSliderShowFood(BaseListener listener);interface BaseListener{void getSuccess(T t);void getFailure();}
}
在看一下实现,和上面的View的思想差不多,请求一类数据定义一个接口。
/*** 作者:GXL on 2016/8/3 0003* 博客: http://blog.csdn.net/u014316462* 作用:数据请求Model*/
public class FoodModel implements FoodModelImpl {@Overridepublic void getGeneralFoodsItem(String sortby, int type, int page, final BaseListener listener) {FoodService service = RetrofitWrapper.getInstance().create(FoodService.class);service.getFoodList(sortby,type,page).subscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread()).map(new Func1>(){@Overridepublic List call(String s) {return HtmlParser.parserHtml(s);}}).subscribe(new Subscriber>() {@Overridepublic void onCompleted() {}@Overridepublic void onError(Throwable e) {listener.getFailure();}@Overridepublic void onNext(List s) {listener.getSuccess(s);}});}@Overridepublic void getFoodDetailTeachItem(String foodlink, final BaseListener listener) {String foodname=foodlink.substring(foodlink.lastIndexOf("/")+1,foodlink.lastIndexOf("."));FoodService service = RetrofitWrapper.getInstance().create(FoodService.class);service.getDetailFood(foodname).subscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread()).map(new Func1() {@Overridepublic FoodDetailTeachItem call(String s) {return HtmlParser.parserHtmlToDetailInPc(s);}}).subscribe(new Subscriber() {@Overridepublic void onCompleted() {}@Overridepublic void onError(Throwable e) {listener.getFailure();}@Overridepublic void onNext(FoodDetailTeachItem foodDetailTeachItem) {listener.getSuccess(foodDetailTeachItem);}});}@Overridepublic void getSliderShowFood(final BaseListener listener) {FoodService service = RetrofitWrapper.getInstance().create(FoodService.class);service.getSliderShowFood().subscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread()).map(new Func1>() {@Overridepublic List call(String s) {return HtmlParser.parserHtmlToSliderShow(s);}}).subscribe(new Subscriber< List>() {@Overridepublic void onCompleted() {}@Overridepublic void onError(Throwable e) {listener.getFailure();}@Overridepublic void onNext(List sliderShowViewItems) {listener.getSuccess(sliderShowViewItems);}});}
}
看到这个数据请求代码,你可能会感到很惊讶,特别简捷,这就是用了RxJava和Retrofit的好处了,下一篇我会重点讲一下他们的应用。
Presenter部分
前面View和Model都定义好了,老大也是时候出场了,为什么说它是老大尼?是因为大部分事情都是Presenter协调View和Model去处理的。看一下代码:
/*** 作者:GXL on 2016/8/3 0003* 博客: http://blog.csdn.net/u014316462* 作用:FoodFragment的Presenter*/
public class FoodFragmentPresenter {private IFoodFragment mIFoodFragment;private FoodModel mFoodModel=new FoodModel();public FoodFragmentPresenter(IFoodFragment mIFoodFragment) {this.mIFoodFragment = mIFoodFragment;}/*** 上拉加载更多* @param sortby* @param lm* @param page*/public void onLoadMore(String sortby,int lm,int page){mFoodModel.getGeneralFoodsItem(sortby, lm, page, new FoodModelImpl.BaseListener() {@Overridepublic void getSuccess(Object o) {List list= (List) o;mIFoodFragment.onLoadMore(list);}@Overridepublic void getFailure() {}});}/*** 下拉刷新* @param sortby* @param lm* @param page*/public void onRefresh(String sortby,int lm,int page){mFoodModel.getGeneralFoodsItem(sortby, lm, page, new FoodModelImpl.BaseListener() {@Overridepublic void getSuccess(Object o) {List list= (List) o;mIFoodFragment.onRefresh(list);}@Overridepublic void getFailure() {}});}/*** 初始化SliderShow*/public void onInitSliderShow(){mFoodModel.getSliderShowFood(new FoodModelImpl.BaseListener() {@Overridepublic void getSuccess(Object o) {List list= (List) o;for (SlideShowView.SliderShowViewItem item:list) {Log.i("TAG", "onInitSliderShow: "+item.getFoodname());}mIFoodFragment.onInitSliderShow(list);}@Overridepublic void getFailure() {}});}
}
从代码中,我们可以清楚的看见,FoodFragmentPresenter里面包含了IFoodFragment的View接口和FoodModel数据请求接口。响应事件时就可以:FoodPresenter的某个函数被响应——–》让FoodModel去获取数据——》数据获取到了让View去加载数据。
还是从一个真实的流程看一下:
比如现在下拉Listview刷新。
1.FoodFragment的listview响应onRefresh()中执行Presenter的onRefresh方法。
public void onRefresh() {mFoodFragmentPresenter.onRefresh("update", 13, 1);}
- mFoodFragmentPresenter.onRefresh(“update”,13,1)方法中会先调用Model进行数据请求,成功后会在回调中将数据加载到View接口中。这样就完成了数据的加载。
/*** 下拉刷新* @param sortby* @param lm* @param page*/public void onRefresh(String sortby,int lm,int page){mFoodModel.getGeneralFoodsItem(sortby, lm, page, new FoodModelImpl.BaseListener() {@Overridepublic void getSuccess(Object o) {List list= (List) o;mIFoodFragment.onRefresh(list);}@Overridepublic void getFailure() {}});}
多看两遍就理解这个流程了,项目代码地址:https://github.com/gxl1240779189/ReIntelligentKitchen,我最近我慢慢完善,争取将最近的技术融入进去,欢迎star一起交流。
本文来自互联网用户投稿,文章观点仅代表作者本人,不代表本站立场,不承担相关法律责任。如若转载,请注明出处。 如若内容造成侵权/违法违规/事实不符,请点击【内容举报】进行投诉反馈!
