編輯:關於Android編程
上一篇博客,我們介紹了項目分包的結構,這一篇我們重點來介紹一下MVP架構在項目中的應用,MVP可以說是MVC模式的一種升級,在MVP出現之前,一般都是用MVC,但是使用MVC有一個很大的缺點就是:通常將Activity作為Controller,xml文件當做View,Model數據請求類不變,但是Activity作為展示界面,通常要處理點擊事件的響應,這就將C和V耦合在了一起,造成的後果就是activity動不動就大篇幅的代碼,後期難以維護和升級。自從用了MVP之後,媽媽再也不要擔心我的Activity類爆炸了。
vcrTzbzJz6GjPC9wPg0KPHA+TW9kZWyjusrHyv2+3bSmwO2jrNK7sOO78cihyv2+3b/iyv2+3aGizfjC58frx/O2vLao0uXU2tXiwO/D5qGjPC9wPg0KPHA+UHJlc2VudGVyo7rKx9fp1q/V36OsysfV5tX9tcTWtNDQyM7O8bXEtdi3vaOs0ruw49K7uPZwcmVzZW50ZXLA78Pm09DSu7j2Vmlld7rNTW9kZWy1xNL908OhozwvcD4NCjxwPnRhbGsgaXMgY2hlYXCjrMjDztLAtL+00rvPwsq1wP2hozwvcD4NCjxoMiBpZD0="2mvp的實例運用">2.MVP的實例運用
先說一下需求
美食傑往上面的數據,如何加載到我們的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;
}
@Override
public String toString() {
// TODO Auto-generated method stub
return title;
}
}
這沒什麼說的,就是需要展示的一些數據。我們看關鍵的MVP用法。先給一個類圖給一個直觀的認識。

下面說明一下:
通常一個功能界面對應一個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);
//初始化sliderView
void 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對象,用來頁面響應時真正的處理請求。
先看一下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 {
@Override
public 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>(){
@Override
public List call(String s) {
return HtmlParser.parserHtml(s);
}
}).subscribe(new Subscriber>() {
@Override
public void onCompleted() {
}
@Override
public void onError(Throwable e) {
listener.getFailure();
}
@Override
public void onNext(List s) {
listener.getSuccess(s);
}
});
}
@Override
public 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() {
@Override
public FoodDetailTeachItem call(String s) {
return HtmlParser.parserHtmlToDetailInPc(s);
}
})
.subscribe(new Subscriber() {
@Override
public void onCompleted() {
}
@Override
public void onError(Throwable e) {
listener.getFailure();
}
@Override
public void onNext(FoodDetailTeachItem foodDetailTeachItem) {
listener.getSuccess(foodDetailTeachItem);
}
});
}
@Override
public void getSliderShowFood(final BaseListener listener) {
FoodService service = RetrofitWrapper.getInstance().create(FoodService.class);
service.getSliderShowFood().subscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread())
.map(new Func1>() {
@Override
public List call(String s) {
return HtmlParser.parserHtmlToSliderShow(s);
}
})
.subscribe(new Subscriber< List>() {
@Override
public void onCompleted() {
}
@Override
public void onError(Throwable e) {
listener.getFailure();
}
@Override
public void onNext(List sliderShowViewItems) {
listener.getSuccess(sliderShowViewItems);
}
});
}
}
看到這個數據請求代碼,你可能會感到很驚訝,特別簡捷,這就是用了RxJava和Retrofit的好處了,下一篇我會重點講一下他們的應用。
前面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() {
@Override
public void getSuccess(Object o) {
List list= (List) o;
mIFoodFragment.onLoadMore(list);
}
@Override
public 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() {
@Override
public void getSuccess(Object o) {
List list= (List) o;
mIFoodFragment.onRefresh(list);
}
@Override
public void getFailure() {
}
});
}
/**
* 初始化SliderShow
*/
public void onInitSliderShow(){
mFoodModel.getSliderShowFood(new FoodModelImpl.BaseListener() {
@Override
public void getSuccess(Object o) {
List list= (List) o;
for (SlideShowView.SliderShowViewItem item:list
) {
Log.i("TAG", "onInitSliderShow: "+item.getFoodname());
}
mIFoodFragment.onInitSliderShow(list);
}
@Override
public 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() {
@Override
public void getSuccess(Object o) {
List list= (List) o;
mIFoodFragment.onRefresh(list);
}
@Override
public void getFailure() {
}
});
}
多看兩遍就理解這個流程了,項目代碼地址:https://github.com/gxl1240779189/ReIntelligentKitchen,我最近我慢慢完善,爭取將最近的技術融入進去,歡迎star一起交流。
Android實現多媒體錄音筆
記事本涉及到的僅僅是對string 的存儲,而且在讀取上並不存在什麼難點,直接用textview顯示便可以了。需要做的主要是使用SQLite對數據進行一個整理。而錄音筆需
微信的錢可以轉到支付寶嗎|微信的錢怎麼轉到支付寶
微信的錢可以轉到支付寶嗎?其實,微信與支付寶,是二大死對頭,都在向移動支付市場發力,所以彼此都不會為對方提供支付入口的。無論是微信,還是支付寶,如果要充值或
Android 底部彈出提示框的解決辦法(使用Activity以及PopupWindow)
本片文章主要談探討了如何實現在底部彈出提示框背景為半透明效果的實現。想要實現此種效果一般有兩種方式一個是使用Activity設置Theme另一種方式就是使用PopupWi
Android自定義控件——自定義屬性
我們在自定義android組件的時候,除了用Java構建出組件的樣子外,有時候還需要去申明一些“屬性”提供給項目使用,那麼什麼是組件