Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> 智能廚房重構-MVP架構

智能廚房重構-MVP架構

編輯:關於Android編程

上一篇博客,我們介紹了項目分包的結構,這一篇我們重點來介紹一下MVP架構在項目中的應用,MVP可以說是MVC模式的一種升級,在MVP出現之前,一般都是用MVC,但是使用MVC有一個很大的缺點就是:通常將Activity作為Controller,xml文件當做View,Model數據請求類不變,但是Activity作為展示界面,通常要處理點擊事件的響應,這就將C和V耦合在了一起,造成的後果就是activity動不動就大篇幅的代碼,後期難以維護和升級。自從用了MVP之後,媽媽再也不要擔心我的Activity類爆炸了。

1.MVP的簡單介紹

這裡寫圖片描述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接口,接口裡面定義數據加載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> mDataList;
    private ArrayList mFoodGeneralList;
    private SimpleAdapter mSimpleAdapter;
    private FoodFragmentPresenter mFoodFragmentPresenter;
    private int mPage = 1;

    private GridView mGridview;
    private SlideShowView mSlideshowView;

    private final String  FOODITEM="fooditem";

    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {
        View v = inflater.inflate(R.layout.foodfragment_main, container, false);
        ButterKnife.bind(this, v);
        mFoodFragmentHead = (LinearLayout) inflater.inflate(R.layout.foodfragment_head, null);
        mGridview = (GridView) mFoodFragmentHead.findViewById(R.id.gridview);
        mSlideshowView = (SlideShowView) mFoodFragmentHead.findViewById(R.id.slideshowView);
        xListView.addHeaderView(mFoodFragmentHead);
        init();
        return v;
    }

    private void init() {
        mFoodGeneralList = new ArrayList<>();
        mAdapter = new FoodGeneralAdapter(getActivity(), mFoodGeneralList);
        xListView.setAdapter(mAdapter);
        xListView.setPullLoadEnable(true);
        xListView.setXListViewListener(this);
        mDataList = new ArrayList>();
        initData();
        String[] from = {"image", "text"};
        int[] to = {R.id.image, R.id.text};
        mSimpleAdapter = new SimpleAdapter(getActivity(), mDataList,
                R.layout.gridview_item, from, to);
        mGridview.setAdapter(mSimpleAdapter);
        mFoodFragmentPresenter = new FoodFragmentPresenter(this);
        if(NetUtil.checkNet(getActivity())) {
            mFoodFragmentPresenter.onInitSliderShow();
            mFoodFragmentPresenter.onRefresh("update", 13, 1);
        }else{
            Log.i("TAG", "init: "+"meiwang");
            loading.setVisibility(View.GONE);
            tip.setVisibility(View.VISIBLE);
            xListView.setVisibility(View.GONE);
        }

        mGridview.setOnItemClickListener(new AdapterView.OnItemClickListener() {

            @Override
            public void onItemClick(AdapterView parent, View view,
                                    int position, long id) {
                {
                    Intent intent = new Intent(getActivity(),
                            FoodTypeActivity.class);
                    Bundle bundle = new Bundle();
                    bundle.putInt("position", position);
                    intent.putExtras(bundle);
                    startActivity(intent);
                }
            }
        });

        xListView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
            @Override
            public void onItemClick(AdapterView parent, View view, int position, long id) {
                List mDatas = mAdapter.returnmDatas();
                FoodGeneralItem fooditem = mDatas.get(position - 2);
                Intent intent = new Intent(getActivity(), FoodTeachActivity.class);
                intent.putExtra("URLLINK",fooditem.getLink());
                startActivity(intent);
            }
        });
    }

    @Override
    public void onDestroyView() {
        super.onDestroyView();
        ButterKnife.unbind(this);
    }


    @Override
    public void onLoadMore(List list) {
        mAdapter.addAll(list);
        mAdapter.notifyDataSetChanged();
        xListView.stopLoadMore();
    }

    @Override
    public void onRefresh(List list) {
        loading.setVisibility(View.GONE);
        tip.setVisibility(View.GONE);
        xListView.setVisibility(View.VISIBLE);
        mAdapter.setDatas(list);
        mAdapter.notifyDataSetChanged();
        xListView.stopRefresh();
    }

    @Override
    public void onInitSliderShow(List list) {
        mSlideshowView.initUI(getActivity(), list);
    }

    @Override
    public void onRefresh() {
        mFoodFragmentPresenter.onRefresh("update", 13, 1);
    }

    @Override
    public void onLoadMore() {
        mPage++;
        mFoodFragmentPresenter.onLoadMore("update", 13, mPage);
    }

    public void initData() {
        for (int i = 0; i < mIconList.length; i++) {
            Map map = new HashMap();
            map.put("image", mIconList[i]);
            map.put("text", mNameList[i]);
            mDataList.add(map);
        }
    }

    @OnClick({R.id.menu, R.id.search})
    public void onClick(View view) {
        switch (view.getId()) {
            case R.id.menu:
                break;
            case R.id.search:
                break;
        }
    }
}

關鍵看一下實現的三個方法理解一下。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 {
    @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的好處了,下一篇我會重點講一下他們的應用。

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() {
            @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一起交流。

  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved