MVP

MVP耦合图示:

image.png

MVP使用交互流程图示:
image.png

MVP全称是Model-View-Presenter,是模型(model)-视图(view)-呈现器(Presenter)的缩写。
Model:业务逻辑和数据处理(数据库存储操作,网络数据请求,复杂算法。耗时操作)
View:对应与Activity,负责View的绘制以及与用户交互
Presenter:负责完成View与Model间的交互(有一点还需注意,presenter是双向绑定的关系,因此,在设计的时候就要注意到接口和抽象的使用,尽可能的降低代码的耦合度,这也是mvp的宗旨)

责任划分
Model:定义并实现获取数据操作(如数据库读取、网络加载)的接口
View:定义并在Activtiy、Fragment等中实现用于界面处理(初始化、数据展示)的接口
Presenter:定义用于调用Model的数据请求方法的接口,实现此接口,并实现Model中定义的数据请求接口
项目结构
image.png
Step 1、编写Model逻辑

数据请求接口(如数据库读取、网络加载)的定义

  /**
     * Model层接口--实现该接口的类负责世界的数据获取操作,如数据库读取、网络加载
     */

    public interface IModel{

        void getData(Model.LoadDataCallback callback);
    }

数据请求接口的实现

    /**
     * 实现IModel接口、负责实际的数据获取操作(数据库读取、网络加载等),然后通过自己的接口(LoadDataCallback)反馈出去
     */

    public class Model implements IModel{

        @Override
        public void getData(final LoadDataCallback callback) {
            //数据获取操作、如数据库查询、网络加载等

            new Thread(){
                @Override
                public void run() {
                    try {
                        //模拟耗时操作
                        Thread.sleep(3000);
                        //获取到了数据
                        String data="我是获取到的数据";
                        //将获取到的数据通过接口反馈出去
                        callback.success(data);
                    } catch (Exception e) {
                        e.printStackTrace();
                        //获取数据失败的回调
                        callback.failure();
                    }
                }
            }.start();
        }
        /**
         * 用于回传请求的数据的回传
         */

        public interface  LoadDataCallback{
            void success(String taskId);

            void failure();
        }
    }
Step2/编写View逻辑

定义用于界面处理(初始化,数据展示)的接口

/**
 * View层接口---执行各种UI操作,定义的方法主要是给Presenter中来调用的
 */
public interface IView {

    void showLoadingProgress(String message);

    void showData(String text);
}

在Activtiy 、Fragment等中对接口的实现:

/**
 * 实现IView接口并实现各种UI操作的方法(其他的业务逻辑在Presenter中进行操作)
 */
public class ViewActivity extends AppCompatActivity implements IView {

    private Button mBtnShowToast;
    private TextView mText;
    private MyHandler mHandler = new MyHandler(ViewActivity.this);
    private IPresenter mPresenter;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_mvp);

        //实例化Presenter,并将实现了IView接口的类传入进去
        mPresenter = new Presenter(ViewActivity.this);

        mBtnShowToast = findViewById(R.id.btn_show_toast);
        mText = findViewById(R.id.text);

        mBtnShowToast.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                //通过Presenter来实现业务逻辑操作,View层只负责UI相关操作
                mPresenter.loadData();
            }
        });
    }

    @Override
    public void showLoadingProgress(final String message) {
        mHandler.post(new Runnable() {
            @Override
            public void run() {
                mText.setText(message);
            }
        });
    }

    @Override
    public void showData(final String text) {
        mHandler.post(new Runnable() {
            @Override
            public void run() {
                mText.setText(text);
            }
        });
    }

    private static class MyHandler extends Handler {

        //弱引用,防止内存泄露
        WeakReference<ViewActivity> weakReference;

        public MyHandler(ViewActivity activity) {
            this.weakReference = new WeakReference<ViewActivity>(activity);
        }

        @Override
        public void handleMessage(Message msg) {
            switch (msg.what) {
                case 1:
                    weakReference.get().mText.setText(msg.what);
                    break;
            }
        }
    }
}
Step3/编写Presenter逻辑(重点)

presenter层很重要,因为MVP模式中,View和Model通过presenter纽带进行交互----
View通过presenter对象来调用Model中数据请求的接口,而Model中数据请求的结果会通过presenter中定义的接口回调给presenter,然后在通过presenter通知给view

定义用于调用Model中的数据请求方法的接口具体实现:

    /**
     * Presenter层接口--控制Model层的数据库操作及调用View层的UI操作来完成“中间人”工作
     */

    public interface IPresenter {

        void loadData();
    }

定义用于调用Model中的数据请求方法的接口,实现此接口,并实现M中定义的数据请求的接口

/**
 * Presenter层接口---控制Model层的数据操作及调用View层的UI操作来完成“中间人”工作.
 * 用于model和view的相关方法的调用
 */
public class Presenter implements IPresenter, Model.LoadDataCallback {

    private final IView mView;
    private final Model mModel;

    public Presenter(IView view) {
        mView = view;
        mModel = new Model();
    }

    @Override
    public void loadData() {
        mView.showLoadingProgress("加载数据中");
        mModel.getData(Presenter.this);
    }

    @Override
    public void success(String data) {
        mView.showData(data);
    }

    @Override
    public void failure() {

    }
}
MVP与MVC区别
MVC结构示意图
image.png
MVP结构示意图
image.png
MVP MVC区别
1.Activity职责不同

Activtiy在MVP中时View层,在MVC中是Controller层,这是MVC 和MVP很主要的一个区别,可以说Android从MVC转向MVP开发也主要是优化Activity的代码,避免Activtiy的代码臃肿庞大

2.View层不同

MVC的View层指的是XML布局文件或者是用Java自定义的View,MVP层的View是Activtiy或者Fragment。使用传统的MVC,其中的View对应的是各种Layout布局文件,但是这些布局文件中并不像web端那样强大,能做的事情非常有限。MVP的View层Activity在实际项目中,随着逻辑的复杂度越来越大,Activtiy臃肿的缺点仍然体现出来了,因为Activtiy中还是充满了大量与View层无关的代码,比如各种事件的处理派发,就如MVC中的那样View层和Controller代码耦合在一起。

3.控制层不同。

MVC控制层是Activtiy,或者是Fragment,Controller对应的是Activity,而Activity中又具有操作UI的功能,我们在实际的项目中也会有很多UI操作在这一层,也做了很多View中应该做的事情,当然Controller层Activity中包含应该做的事情,比如各种事件的派发回调,而且在一层中我们会根据时间再去调用Model层操作数据,所以这种MVC的方式在实际项目中,Activtiy所在的Controller是非常重要的,各层次之间的耦合情况也比较严重,不方便单元测试。MVP的控制层是Presenter,里面没有很多的实际东西,主要是做Model和View层的交互。

4.关系链不同

MVP中Model层与View层是没有关系的,彼此不会通讯和操作,Model与View的通讯都是Presenter层来传达的。但是在MVC中,Model和View是存在交互的。比如我们自定义的View空间里面肯定要使用Model的数据,View也要根据不同的Model数据做出不同的展现。在MVP中,接口就可以完成。

5.适用范围不同

在Android中,MVP和MVC都有自己的适用情况。使用MVP可以更好的解耦三大模块,模块之间比较清晰,也很方便使用MVP来组件化架构整体项目。在组件化的Module或者中间件我们可以使用MVC,Module或者中间件中不会存在很复杂的View层,使用MVC更加方便

6.交互方式不同

MVP通讯交互基本都是通过接口的,MVC中的通讯交互很多时候都是调用对象的方法

7.实现方法不同

MVC和MVP的Model几乎是一样的,都是处理数据,只要不在Activity或者Fragment中请求数据,其他的所有控制都放在Activity或者Fragment中,这样写基本就是MVC,但是容易造成Activtiy代码冗余。用MVP则需要写很多View和Presenter接口来实现模块之间的通讯,会增加很多类。

相同点

优点:
降低耦合度
模块职责画风明显
利于测试驱动开发
代码复用
隐藏数据
代码灵活性
缺点:
额外的代码复杂度及学习成本

不同点:
MVP模式:
View不直接与Model交互,而是通过与Presenter交互来与Model间接交互
Presenter与VView的交互是用过接口来进行的,更有利于添加单元测试
通常View与Presenter是一对一的,但复杂的View可能绑定多个Presenter来处理逻辑,业务相似的时候也可以多个View共享一个Presenter
MVC模式:
View可以与Model直接交互
Controller是基于行为的,并且可以被多个View共享
Controller可以负责决定显示哪个View

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 219,589评论 6 508
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 93,615评论 3 396
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 165,933评论 0 356
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,976评论 1 295
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,999评论 6 393
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,775评论 1 307
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,474评论 3 420
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,359评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,854评论 1 317
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 38,007评论 3 338
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 40,146评论 1 351
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,826评论 5 346
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,484评论 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 32,029评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,153评论 1 272
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,420评论 3 373
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 45,107评论 2 356

推荐阅读更多精彩内容