關於MVP架構的項目實戰總結

前言

前段時間做了一個項目,好朋友搭好了MVP框架,現在項目結束了,我想總結一下其中的關鍵點,方便以後自己搭建架構。

MVP介紹

什麼是MVP架構呢,以我本人的理解,項目代碼模塊分爲模型、視圖和展現層。視圖層不能直接和模型層直接關聯或調用。他們直接需要通過展現層來交互。MVP的前身是MVC。爲什麼要分層呢,不分層不是一樣可以實現功能,我在activity中寫視圖,獲取數據,顯示數據,保存數據。這樣也ok啊。那我自己的感觸來說,分層的好處比不分層的多。我本人長期維護ANDROID原生的APP,比如瀏覽器,聯繫人,短信,電子郵件,這些app基本上沒有分層架構,如果我要加一個功能,那麼修改的時間是非常多的,修改了這個功能還需要進行測試,因爲我不能保證是否影響到其他模塊。同時要掌握整個APP的代碼模塊,才能夠比較順利的完成需求。

09年的時候,我在廈門培訓,當時培訓機構就是給我們講解MVC架構,實現架構的3個技術是 Struts Spring Hibernate,我當時覺得這個東西沒有什麼了不起,也就那樣,我在寫代碼的時候,發現就是按照這些模板來寫就可以了,完全不要東腦子,我覺得沒有前途。特別是那些javebean,寫的特別簡單,幾個屬性,加上get set方法,就ok了。但是現在想想,自己當時非常的圖樣 圖森破。

在這裏插入圖片描述

  • Model 模型層
    modele層主要做哪些事情呢?主要是獲取數據。數據存儲大概有這麼幾種:數據庫,網絡服務器數據,sharepreference。最後,我們還可以對數據的來源進行抽象,通過代理模式來進行獲取對應的實例對象,實例對象再實際的返回數據。
    Model 與 Presenter層如何交互呢?考慮這樣一種情況,當展現層調用模型層方法,那麼模型層要方法網絡服務器,訪問網絡服務器需要時間,那麼展現層必須等等;而當模型層獲取數據時,如何通知展現層呢;所以這些情況就比較複雜,那麼我們需要使用觀察者模式,展現層將請求提交給模型層,模型層在獲取到信息後回調展現層。目前非常流行的技術是RXJava
  • Presenter 展現層
    Presenter展現層是用來隔離視圖層與模型層。視圖層對模型層的操作主要有對數據的請求,保存,修改等。展現層通過對這些操作進行統一管理,減少view層的邏輯處理,從而達到簡化邏輯。比如我們用戶點擊了一個選項,需要顯示此選項的詳細信息。視圖層只傳送選項的id,模型層再加上通用請求參數(用戶id,設備信息,時間),去服務器請求數據。模型層這些通用參數,模型層可以繼承一個父類,父類裏面實現通用參數創建、管理。
  • View 視圖層
    視圖層,很明顯,就是要現實數據給用戶,用戶在視圖界面可以進行操作。我們展現數據時,一般會用到RecyclerView控件,和RecyclerView的搭檔,RecyclerView.Adapter。如果要在一個activity中展示多個不同的界面,那麼我們需要Fragment。在很多時候,關鍵功能使用標準控件無法達到效果,那麼我們需要進行自定義控件。

簡單代碼

下面我就貼出部分代碼,說明MVP的簡單實現。

  1. model層
    protected ApiService api = Api.getApiService();//在BaseModel父類中定義
    
public class AppUpdateModel<T> extends BaseModel {

    public void getUpdateInfo(Context ctx, RequestBody currentInfo, ObservableTransformer<T, T> transformer,
                              final ObserverResponseListener<AppUpdateBean> listener) {
        Observable<AppUpdateBean> obs = api.getUpdateInfo(currentInfo);
        subscribe(ctx,obs,transformer,listener,false,false);
    }
}
  1. 展現層 Presenter

public class AppUpdateContact {
    public interface View extends BaseView{
        void updateView(AppUpdateBean bean);

        void onDownLoad(File apkFile);
    }

    public interface Presenter extends BasePresenter{
        void downloadApk(AppUpdateBean appInfo);
    }
}

public class AppUpdatePresenter<T extends AppUpdateContact.View> extends
        BasePresenterImpl<T> implements AppUpdateContact.Presenter {
    AppUpdateModel mModel;
    public AppUpdatePresenter(Context ctx, T view) {
        super(ctx, view);
        mModel = new AppUpdateModel<>();
    }

    @Override
    public void loadData() {
        Map<String,String> requestParam = getBaseRequestParam();
        mModel.getUpdateInfo(mContext, createRequestBody(requestParam), mView.bindLifecycle(), new ObserverResponseListener<AppUpdateBean>() {
            @Override
            public void onNext(AppUpdateBean appUpdateBean) {
                mView.updateView(appUpdateBean);
            }

            @Override
            public void onError(ExceptionHandle.ResponeThrowable e) {

            }
        });
    }
  1. View 視圖層
public class AppUpdateActivity extends BaseActivity<AppUpdateContact.View,
        AppUpdateContact.Presenter> implements AppUpdateContact.View {

    private final String TAG = AppUpdateActivity.class.getSimpleName();

    @BindView(R.id.version_detail)
    TextView mVersionDetail;
    @BindView(R.id.version)
    TextView appVersion;
    @BindView(R.id.version_date)
    TextView versionDate;
    @BindView(R.id.current_version)
    TextView currentVersion;

    @BindView(R.id.download_app)
    Button download;

    private AppUpdateBean appInfo;

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        //setContentView(R.layout.activity_app_update);
    }

    @Override
    public AppUpdateContact.View createView() {
        return null;
    }

    @Override
    public AppUpdateContact.Presenter createPresenter() {
        return new AppUpdatePresenter(mContext, this);
    }

    @Override
    public int getLayout() {
        return R.layout.activity_app_update;
    }

    public void init() {
        iv_title.setText("版本更新");
        getPresenter().loadData();
        updateDownloadBtn();
    }
...
    @Override
    public <T> ObservableTransformer<T, T> bindLifecycle() {
        return bindToLifecycle();
    }

    @Override
    public void updateView(AppUpdateBean bean) {
        if (bean.getSuccess() == AppUpdateBean.SUCCESS) {
            appInfo = bean;

            mVersionDetail.setText(bean.getRemark());

            appVersion.setText(bean.getVersion());
            CharSequence txVersion = getResources().getString(R.string.tx_current_version, BuildConfig.VERSION_NAME);
            currentVersion.setText(txVersion);


            versionDate.setVisibility(View.GONE);
            Log.i(TAG, bean.toString());
        }
        updateDownloadBtn();
    }

    @Override
    public void onDownLoad(File apkFile) {
        Log.i(TAG, "installApk");
        installApk(apkFile);
        ProgressDialogUtil.dismiss();
    }

    @OnClick(R.id.download_app)
    public void onClick(View view) {
        switch (view.getId()) {
            case R.id.download_app:
                if (appInfo != null && isVersionLate()) {
                    getPresenter().downloadApk(appInfo);
                    ProgressDialogUtil.showProgressDialog(mContext);
                }
                break;
        }
    }

    private boolean isVersionLate() {
        String current = BuildConfig.VERSION_NAME;
        String newVersion = appInfo != null ? appInfo.getVersion() : "";
        return newVersion.compareTo(current) > 0;
    }

    private void updateDownloadBtn(){
        if (isVersionLate()) {
            download.setText(R.string.tx_download_apk);
        } else {
            download.setText(R.string.tx_download_new);
        }
    }

}

展現層中使用了butterknife技術,控件的初始化全部靠他,不用我們自己去寫findviewbyId. @OnClick(R.id.download_app)使控件注入點擊事件。

結語

目前我們的項目中沒有使用Dagger2,所以view層的 presenter 需要硬編碼寫入,同樣presenter層的model也需要硬性寫入,後期可以考慮使用依賴注入。使代碼更靈活。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章