1. 程式人生 > >Android MVP模式的化簡深入理解

Android MVP模式的化簡深入理解

 

 

       網上關於MVP的冗長教程已經很多了,自己結合所做的MVP專案儘量簡潔,簡單,大白話的方式記錄心得,為了日後遺忘的差不多了能迅速把記憶抓起來。一圖勝千言,先上圖。圖1是mvp的框架流程圖:

                          

                                                                                   圖1     

 

     簡單介紹下MVP三劍客:Model,View, Presenter,重點會結合Demo去剖析。

     Model:  它是涉及資料管理的介面,簡單的說,只要是程式碼處理資料,都會由這個Model來負責。

     View: 你能看到的都是View , 作為使用者能看到手機上的介面都是View檢視層,作用僅僅是繪製UI元素和響應UI操作,比如點選UI元素。

     Presenter:   Presenter是三劍客的核心部分,app的邏輯程式碼基本全寫在Presenter中了,從圖1就能看出來,它承上啟下,聯絡著Model層和View層

     需要注意的是,View層不和Model層直接聯絡,需要Presenter為中介,上面說的理論畢竟有些泛泛之談,結合下面的Demo繼續具體的分析。

 

                                                 

                                                                               圖2

 

     Demo實現的效果很簡單,點選介面上的搜尋按鈕,會發送http協議獲取某個城市的經緯度,當獲取到http請求回執後,反序列化Json,然後重新繪製介面,顯示經緯度。從MVP的模式去講,這個包含搜尋Button的,點選搜尋後彈出的轉圈等待介面就是View層,當響應點選事件之後,View層就會通知Presenter層,讓Presenter去傳送獲取經緯度的http協議,並且在Presenter中監聽http協議的回執,若協議收發成功,那麼presenter就會通知View層去重新繪製UI。下面貼出具體程式碼進行理解

 

/**
 * Created by xjc on 2018/11/26.
 */

public interface MainPresenter {


    interface View extends BaseView {
        //通知介面(View層)重新整理的邏輯函式
        void refreshViewMistakeIntruductionList( LocationResponseBean bean);
    }

    interface Model {
        //傳送獲取經緯度座標協議
        void getLonLat();
    }

}

     一個Presenter是由兩部分組成的:Presenter介面和Presenter的具體實現(Impl),Presenter介面中包含了兩個interface:View和Model。 View介面的抽象方法就是聲明瞭Presenter層和View層之間的聯絡,要和View之間有怎樣的互動,比如上面View介面中的方法就是通知介面重新整理。Model介面就是MVP中Model層要實現的功能,上述程式碼Model層中抽象方法就是為了傳送經緯度的http協議。這樣一目瞭然,這個Presenter的功能有兩個,一是獲取經緯度,二是通知介面重繪,但是具體怎麼幹,怎麼一點點寫出來,都會交給這個Presenter介面的實現類。

/**
 * Created by xjc on 2018/11/26.
 */

public class MainPresenterImpl extends BasePresenter<MainPresenter.View> implements MainPresenter.Model{

    private ApiHttpService apiHttpService;


    @Inject
    public MainPresenterImpl(ApiHttpService apiHttpService) {
        this.apiHttpService = apiHttpService;
    }


    @Override
    public void getLonLat() {
        JSONObject jsonObject = new JSONObject();
        try {
            jsonObject.put("a","大連");
        } catch (JSONException e) {
            e.printStackTrace();
        }
        //retrofit2.0傳送http請求
        invoke(apiHttpService.fetchLocation(jsonObject.toString()),new Callback<LocationResponseBean>(){
            @Override
            public void onResponse(LocationResponseBean bean){

                mView.refreshViewMistakeIntruductionList(bean);
            }
        });
    }
}

  可以看到實現類繼承並實現了presenter介面中的View和Model介面,若協議收發成功,那麼會調Presenter介面中View interface的方法,來通知介面該做一些XX操作了

   mView.refreshViewMistakeIntruductionList(bean);

下面來看一下主介面(View層)

/**
 * Created by xjc on 2018/11/26.
 */
public class MainActivity extends IBaseActivity<MainPresenterImpl> implements MainPresenter.View {

    private Toast mToast = null;
    @BindView(R.id.tv_location)
    TextView tv_location;
    @BindView(R.id.btn_search)
    Button btn_search;


    @Override
    protected int getLayoutId() {
        return R.layout.activity_main;
    }

    @Override
    protected void loadData() {

    }

    @Override
    protected void initView() {

    }

    @Override
    protected void initInject() {
        DaggerMainComponent.builder().apiHttpModule(new ApiHttpModule()).build().injectMain(this);
    }


    @Override
    public void refreshViewMistakeIntruductionList(LocationResponseBean bean) {
        //獲取到資料,取消轉圈
        dismiss();
        //重繪text
        tv_location.setText(bean.getLat()+","+bean.getLon());

    }


    @OnClick(R.id.btn_search)
    public void  searchLocation(View view) {

        //傳送http請求
        mPresenter.getLonLat();
        //轉圈等待
        createLoading();
    }


    @Override
    public void setState(int state) {

    }
}

   可以看到主介面只實現了Presenter的View介面,這就是部落格最開始的流程圖中View層不能和Model層直接建立聯絡的具體程式碼實現,當Presenter實現類的 mView.refreshViewMistakeIntruductionList(bean)被執行的時候,作為子類的MainActivity中的覆寫函式會被執行,取消轉圈並且重繪UI

 @Override
    public void refreshViewMistakeIntruductionList(LocationResponseBean bean) {
        //獲取到資料,取消轉圈
        dismiss();
        //重繪text
        tv_location.setText(bean.getLat()+","+bean.getLon());

    }

     由此,MVP的一整套流程都在這個Demo中完美的實現了,這也是我認為搭建MVP專案最簡單,最方便的寫法。Demo已打包上傳:https://download.csdn.net/download/crystal_xing/10811027,關於MVP中所用的依賴注入框架Dagger2,會用同樣的Demo再寫一篇新的部落格進行總結分析。