关于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也需要硬性写入,后期可以考虑使用依赖注入。使代码更灵活。

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