关于MVP分层架构在项目中的实际运用

973 阅读5分钟

关于MVP的基本知识网上已经有很多了,但是很多都只是Demo,毕竟Demo跟实际运用之间还有无数个Debug,其实一开始我也看了很多关于MVP的介绍,其中有谷歌官方的Demo,还有很多技术博客,那个时候就觉得自己知道什么是MVP了,后来真正在自己项目中运用的时候,才发现并不是那么简单,不过经过一番折腾,逐渐对MVP有了比较深层次的认识,所以今天记录分享一下。

MVP结构示意图
MVP结构示意图

我自己画了一个关系图,也就是最简单的MVP结构示意图,我在这里并不会再解释什么是MVP,今天我想把所有的认知转化为代码,也就是图中的关系图,他们之间的关系我全部都是用Callback来进行联系的,也就是之前说的引用。

M层

  • 这里的M层不是传统意义上的Model,我更倾向于认为他是一个ModelManager,就是一个数据处理中心,可以处理网络数据,数据库,文件以及关于Android中的四大组件的交互包含BroadcastReceiver,Service中的,都可以集中在这里面处理,有很长一段时间对于M的认知都是觉得就是个实体类,那个时候还以为自己掌握地很透彻,最后发现自己理解的其实是不对的,MddelManager持有Presenter的引用,M处理完数据之后通过Callback回调Presenter,Presenter由于持有View的引用,所以可以回调View

V层

  • V就是指View(界面),往大了说是Activity或者Fragemnt,往小了说可以是一个Dialog、Toast或者Snakbar,具体就是直接跟用户进行打交道的,View会实现Callback接口,然后传递给Presenter,然后Presenter会去ModelManager进行交互,然后数据处理完成之后,会通过Callback回调回来,这样就完成了一个闭环

P层

  • P就是Presenter,主持人其实挺形象的,就起一个客串的作用,相当于一座桥,来连接Vie跟ModelManger,很多文章是把逻辑在Presenter中进行处理的,我觉得不是很好,我认为在Modelmanager里面处理比较好,这样解耦的更彻底,毕竟Presenter只是个中间的信使而已,不应该处理过多的逻辑。

关系搞清楚了,其实代码实现就比较简单

M层代码

public class MainManager {
    private ViewCallBack mViewCallBack;

    public MainManager(ViewCallBack viewCallBack) {
        this.mViewCallBack = viewCallBack;
    }

    public void getData() {
        mViewCallBack.refreshView(1, "数据");
    }
}

这里面只是写了一个模板,可能一个界面需要多种数据处理方式,那么就根据需求在重新定义几个方法即可

V层代码

public interface ViewCallBack<V> {

    /**
     * @param code code:0:有数据,1:数据为空,2:加载失败
     * @param data 定义好的数据类型
     */

    void refreshView(int code, V data);
}

这里的V采取泛型的原因在于每个界面需要获取的数据不一样,所以用泛型加以区分,当一个界面需要获取的接口很多,或者得到的数据结果类型不太一致的时候,这里的泛型就需要用Object来指定,然后在refreshView中通过数据的类型来判断需要刷新的数据

P层代码

public class MainPresenter {
    private ViewCallBack mViewCallBack;
    private MainManager mMainManager;

    public MainPresenter(ViewCallBack viewCallBack) {
        this.mViewCallBack = viewCallBack;
        mMainManager = new MainManager(mViewCallBack);
    }

    public void getData() {
        mMainManager.getData();
    }
}

P层代码的方法跟Manager对应,然后处理M层跟V层的Callback即可,但是注意Presenter是一个对象,需要在界面销毁的时候置空,防止内存泄露

我在demo中只是简单写了一个改变Text的值,当然在Manager里面可以进行任何你想要的操作,因为是采用接口回调,运行一下看看效果

MVP效果图
MVP效果图

持续封装

上面的只是一个Demo,下面进行封装抽取,方便集成到真正的项目中去

  1. M层封装
public abstract class BaseBeanManager {

    protected ViewCallBack mViewCallBack;
    protected HashMap<String, String> paramMap;

    public BaseBeanManager(ViewCallBack modelCallBack) {
        mViewCallBack = modelCallBack;
    }
    public abstract void getData();
}
  1. V层封装

 public abstract class BaseActivity<T extends BasePresenter, V> extends AppCompatActivity implements ViewCallBack<V> {
    public T presenter;//泛型定义Presenter
    @TargetApi(Build.VERSION_CODES.M)
    @Override
    protected void onCreate(Bundle bundle) {
        super.onCreate(bundle);
        setContentView(getLayoutId());
        presenter = initPresenter();
        initViews();
        initListener();
    }

    @Override
    protected void onResume() {
        super.onResume();
        //初始化Presenter
        if (presenter == null)
            presenter = initPresenter();
            //添加Callback
        presenter.add((ViewCallBack) this);

    }
    protected abstract int getLayoutId();

    protected abstract void initViews();

    protected abstract void initListener();//初始化监听事件

    protected abstract T initPresenter();//初始化Presenter

    @Override
    protected void onDestroy() {
        super.onDestroy();
        //生命周期结束时销毁callback,并置空presenter
        if (presenter != null){
             presenter.remove();
             presenter = null;

        }
    }
}
  1. P层封装
public abstract class BasePresenter {
    protected BaseBeanManager mBeanManager;//定义基类manager
    protected HashMap<String, String> paramMap = new HashMap<>();
    protected ViewCallBack mViewCallBack;

    public BasePresenter(ViewCallBack viewCallBack) {
        mViewCallBack = viewCallBack;
    }


    public void add(ViewCallBack viewCallBack) {
        this.mViewCallBack = viewCallBack;
    }

    public void remove() {
        this.mViewCallBack = null;
    }
    //默认的获取数据的方法
    protected abstract void getData();


}

使用

  1. M层
public class MainManager extends BaseBeanManager {

    public MainManager(ViewCallBack modelCallBack) {
        super(modelCallBack);
    }

    public void getData() {
        mViewCallBack.refreshView(1, "MVP返回的数据");
    }
}

2.V层

public class MainActivity extends BaseActivity<MainPresenter, String> implements ViewCallBack<String> {
    private TextView tvDemo;
    private Button btnGet;
    @Override
    protected int getLayoutId() {
        return R.layout.activity_main;
    }

    @Override
    protected void initViews() {
        tvDemo = (TextView) findViewById(R.id.tv_demo);
        btnGet = (Button) findViewById(R.id.btn_get);
    }

    public void initListener() {
        btnGet.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                presenter.getData();
            }
        });
    }

    @Override
    protected MainPresenter initPresenter() {
        return new MainPresenter(this);
    }

    @Override
    public void refreshView(int code, String data) {
        tvDemo.setText(data);
    }

}
  1. P层
public class MainPresenter extends BasePresenter {

    public MainPresenter(ViewCallBack viewCallBack) {
        super(viewCallBack);
    }


    public void getData() {
        mBeanManager = new MainManager(mViewCallBack);
        mBeanManager.getData();
    }
}

本身是不想贴这么多代码的,但是只有对比才能发现,MVP由于解耦地比较彻底,所以满足单一职责原则,新增了很多类,封装之后,即使新建的类变多了,每个类都需要一个相应的Presenter,但是代码量很少,所以看起来逻辑比较清楚

这就是我的项目中正在使用的的MVP,刚开始从MVC转换过来的时候很不习惯,后来折腾了一阵子,发现其实挺好用的。

项目下载地址