Android笔记:MVP框架搭建

525 阅读4分钟

MVP模式简介

MVP(Model-View-Presenter)架构设计,是当下较为流行开发模式,目前主要以Google推出的TodoMVP为主

MVP模式解决了MVC中存在的分层问题,Presenter层被突出强调,实际上也就是真正意义上实现了的MVC

MVP不是一种框架,它实际上更类似一种分层思想,一种接口约定,具体体现在下面:

  • 定义IView接口,并且在接口中约定View层的各种操作,使用android.view.View的子类以xml构建文件构建起的布局和Activity/Fragment作为布局控制器,实现IView这个View层的接口,View层的实际实现类保留一个IPresenter接口的实例.
  • 定义IPresenter接口,并且在接口中约定Presenter层的各种操作.可以使用一个与View无关的类实现它,一般是XxxPresenterImpl.通常情况下Presenter层会包含Model层的引用和一个IView接口的引用,但不应该直接或者间接引用View层android.view.View的子类,甚至是操作的参数中也最好不要有android.view.View的子类传进来,因为它应该只负责业务逻辑和数据的处理并通过统一的接口IView传递到View层.
  • 不需要为Model层定义一个IModel的接口,这一层是改造最小的.以前该怎么来现在也差不多该怎么来.但是现在Presenter把它和View隔开了, Presenter就可以作为一段独立的逻辑被复用.

本项目包结构

  • MVP
    • controller 契约类,用于绑定 IView 和 IPresenter
    • model 数据获取类,用于获取网络或者本地的数据
    • presenter 主导处理 model 的数据和运算将处理好的数据提交到 view中显示
    • view 实际上展示的页面,包括 activity,fragment,dialog和自定义控件等
    • api 网络接口信息
    • bean 数据基类
    • daoManager 数据库操作类
    • utils 工具类

话不多说直接上代码最直接: demo 下载(gitHub)


BaseController 实现

BaseController 绑定了 view 和 presenter 的关系

public interface IBaseActivityController extends IController{
    /**
     * 基础View应有的方法 覆盖activity常用方法,开放到presenter调用
     */
    interface IView extends IController.IView{

        Intent getIntent();

        void startActivity(Class className);
        void startActivity(Intent intent);
        void startActivityForResult(Class className, int requestCode);
        void startActivityForResult(Intent intent, int requestCode);
        void showTips(String msg);
        void setResult(int resultCode, Intent data);
        void setResult(int resultCode);
    }

    /**
     * 基础Presenter 应有的方法 应当绑定Activity生命周期
     */
    interface IPresenter extends IController.IPresenter{


        void onStop();

        void onStart();

        void onPause();

        void onResume();

        void onDestroy();

        void onActivityResult(int requestCode, int resultCode, Intent data);
    }
}

BaseActivity 的实现

baseActivity 应该需要绑定 BasePresenter 中的各个生命周期,以便于后面调用,还应当提供一些 Presenter 中可能需要使用的方法


    public abstract class BaseActivity<T extends IBaseActivityController.IPresenter> extends AppCompatActivity implements IBaseActivityController.IView {

    private Unbinder mUnbinder;
    View rootLayout;
    protected Context mContext;
    protected T mPresenter;

    @Override
    protected void onStop() {
        super.onStop();
        if (mPresenter != null)
            mPresenter.onStop();
    }

    @Override
    protected void onStart() {
        super.onStart();
        if (mPresenter != null)
            mPresenter.onStart();
    }

    @Override
    protected void onPause() {
        super.onPause();
        if (mPresenter != null)
            mPresenter.onPause();
    }

    @Override
    protected void onResume() {
        super.onResume();
        if (mPresenter != null)
            mPresenter.onResume();
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        if (mPresenter != null)
            mPresenter.onDestroy();
        if (EventBusUtils.isRegistered(this)) {
            EventBusUtils.unregister(this);
        }
        if (mUnbinder != null)
            mUnbinder.unbind();
    }

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN);
        initSystemData();
        setContentView(setContentLayout());
        mContext = this;
        mUnbinder = ButterKnife.bind(this);
        initView();
    }

    /**
     * 初始化控件
     */
    private void initView() {
        mPresenter = initPresenter();
        rootLayout = getRootLayout();
        initData();
        initEvent();
    }


    /**
     * 获得根布局
     *
     * @return 根布局
     */
    @NonNull
    protected abstract View getRootLayout();

    /**
     * 获得 Presenter
     *
     * @return Presenter
     */
    protected abstract T initPresenter();

    /**
     * 根据 class 直接跳转 Activity
     *
     * @param className class文件 X.class
     */
    @Override
    public void startActivity(Class className) {
        Intent intent = new Intent(mContext, className);
        startActivity(intent);
    }

    public void startActivity(Class className, String key, String str) {
        Intent intent = new Intent(mContext, className);
        intent.putExtra(key, str);
        startActivity(intent);
    }

    @Override
    public void startActivityForResult(Class className, int requestCode) {
        Intent intent = new Intent(mContext, className);
        startActivityForResult(intent, requestCode);
    }

    @Override
    protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
        super.onActivityResult(requestCode, resultCode, data);
        mPresenter.onActivityResult(requestCode, resultCode, data);
    }

    /**
     * 初始化系统参数,在页面初始化之前
     */
    protected void initSystemData() {
    }

    /**
     * 初始化页面参数,在界面初始化之后
     */
    protected abstract void initData();

    /**
     * 返回当前页面布局文件
     *
     * @return @LayoutRes R.layout.x
     */
    @LayoutRes
    protected abstract int setContentLayout();

    /**
     * 事件集
     */
    protected void initEvent() {
    }


    /**
     * 显示提示
     *
     * @param msg
     */
    @Override
    public void showTips(String msg) {
        runOnUiThread(new Runnable() {
            @Override
            public void run() {
                if (rootLayout != null)
                    Snackbar.make(rootLayout, msg, Snackbar.LENGTH_LONG)
                            .setActionTextColor(getColor(R.color.colorAccent))
                            .setAction("确定", null)
                            .show();
            }
        });
    }


    /**
     * 显示提示
     *
     * @param msg
     */
    public void showTips(String msg, View.OnClickListener listener) {
        runOnUiThread(new Runnable() {
            @Override
            public void run() {
                if (rootLayout != null)
                    Snackbar.make(rootLayout, msg, Snackbar.LENGTH_LONG)
                            .setActionTextColor(getColor(R.color.colorAccent))
                            .setAction("确定", listener)
                            .show();
            }
        });
    }
}

BasePresenter 的实现

basePresenter 用于接收处理数据,并且将处理好的数据提交给 View 显示

    public abstract class BasePresenter<V extends IBaseActivityController.IView> implements IBaseActivityController.IPresenter {

    protected V mView;
    protected Context mContext;

    public BasePresenter(V mView, Context mContext) {
        this.mView = mView;
        this.mContext = mContext;
    }


    @Override
    public void onStop() {
    }

    /**
     * 获取意图
     *
     * @return
     */
    protected Intent getIntent() {
        return mView.getIntent();
    }

    /**
     * 关闭页面
     */
    protected void finish() {
        mView.finish();
    }

    /**
     * 跳转页面
     *
     * @param className 类名
     */
    protected void startActivity(Class className) {
        mView.startActivity(className);
    }

    /**
     * 跳转页面
     *
     * @param intent 意图
     */
    protected void startActivity(Intent intent) {
        mView.startActivity(intent);
    }

    protected void startActivity(Class className, String key, String str) {
        Intent intent = new Intent(mContext, className);
        intent.putExtra(key, str);
        mView.startActivity(intent);
    }

    @Override
    public void onStart() {

    }

    @Override
    public void onPause() {
    }

    @Override
    public void onResume() {

    }

    @Override
    public void onDestroy() {
    }

    /**
     * 关闭页面
     */
    protected void finishResult(int resultCode) {
        mView.setResult(resultCode);
        mView.finish();
    }


    /**
     * 关闭页面
     */
    protected void finishResult(int resultCode, Intent data) {
        mView.setResult(resultCode, data);
        mView.finish();
    }

    @Override
    public void onActivityResult(int requestCode, int resultCode, Intent data) {

    }