Android开发之初识MVP模式

一、什么是MVP

在介绍MVP之前,大家一定会想到MVC,我们首先简单介绍一下MVC,因为掌握了MVC对我们学习MVP是有很大帮助的。

MVC 模式代表 Model-View-Controller(模型-视图-控制器) 模式。这种模式用于应用程序的分层开发。

  1. Model(模型) - 模型代表一个存取数据的对象或 JAVA POJO。它也可以带有逻辑,在数据变化时更新控制器。比如数据库存取操作,网络操作,复杂的算法,耗时的任务等都在model层处理。
  2. View(视图) - 视图代表模型包含的数据的可视化。XML布局可以视为V层,显示Model层的数据结果。
  3. Controller(控制器) - 控制器作用于模型和视图上。它控制数据流向模型对象,并在数据变化时更新视图。它使视图与模型分离开。在Android中,Activity处理用户交互问题,因此可以认为Activity是控制器,Activity读取V视图层的数据,控制用户输入,并向Model发送数据请求。
MVC

MVC模式有很多优点:
(1)耦合性低。所谓耦合性就是模块代码之间的关联程度。利用MVC框架使得View(视图)层和Model(模型)层可以很好的分离,这样就达到了解耦的目的,所以耦合性低,减少模块代码之间的相互影响。
(2)可扩展性好。由于耦合性低,添加需求,扩展代码就可以减少修改之前的代码,降低bug的出现率。
(3)模块职责划分明确。主要划分层M,V,C三个模块,利于代码的维护。

既然MVC模式这么厉害,那为什么还要发明MVP?因为使用MVC模式进行Android项目开发,随着项目的逐渐庞大,会逐渐显露出MVC模式在Android开发上的弊端:View层的XML文件能处理的事情非常有限,而作为Controller的Activity又天生具有操作UI的功能,我们在实际的项目中也会有很多UI操作在这一层,做了很多View中应该做的事情;当然Controller中也包含Controller应该做的事情,比如各种事件的派发回调,而且在这层中我们还会根据事件再去调用Model层操作数据,所以这种MVC的方式在实际项目中,Activity所在的Controller是非常臃肿的,各层次之间的耦合情况也比较严重,不方便单元测试。

讲了半天MVC,主角也该登场了。

MVP作为MVC的“进化版”,最大的改进就是它彻底剥离了视图层和业务逻辑层,让各层分工更为明确,逻辑更为清晰,代码扩展性更高,后期代码迭代更新更加容易,同时也方便了单元测试的编写。

  • View仅仅负责实现单纯的、独立的UI操作,尽量不要去维护数据(View层指Activity、Fragment这类层级)
  • Model负责处理数据请求、业务逻辑,不涉及UI操作
  • Presenter是MVP体系的控制中心,负责给View和Model安排工作 ,什么时候调用Model处理逻辑,什么时候调用View反应结果,都是Presenter说了算
  • View与Model均以接口的形式出现在Presenter中,Presenter通过调用 View与Model的实现接口,来操作 View与Model;同时Presenter也是以接口的形式出现在View中,这样Presenter与View就是通过接口相互依赖了
  • Presenter是主动方,View是被动方,对于绑定到View上的数据,不是View调用Presenter主动拉取数据,而是Presenter主动将数据推给View
MVP

二、MVP的简单使用

1、定义网络请求回调接口,P层通过该接口回调通知V层

public interface IRequestView {
    /**
     * 成功
     */
    void succeed(BaseResponse baseResponse);
    /**
     * 失败
     *
     * @param message 错误提示消息
     */
    void failed(String message);
}

2、Model层负责接收来自Presenter层的数据,并开始处理数据(发起网络请求)

//登录接口
public interface IUserModel {
    /**
     * 密码登录
     *
     * @param userName 用户名
     * @param password 密码
     */
    void loginByPassword(Context context, String userName, String password, IRequestView requestView);
}
###############################################################
//实现登录请求
public class UserModel implements IUserModel {
    /**
     * 密码登录
     *
     * @param userName 用户名
     * @param password 密码
     */
    @Override
    public void loginByPassword(Context context, String userName, String password, IRequestView requestView) {
        HashMap<String, Object> map = new HashMap<>();
        map.put("userName", userName);
        map.put("password", password);
        RetrofitManager.getInstance(context).createReq(ApiService.class)
                .signIn(map)
                .subscribeOn(Schedulers.newThread())
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe(new BaseObserver(context, requestView));
    }
}

3、中间层Presenter主要负责把来自View层的数据传递给Model,Model层处理完成后再经由Presenter返回给View层用于展示

public interface IUserPresenter {
    /**
     * 密码登录
     *
     * @param userName 用户名
     * @param password 密码
     */
    void loginByPassword(String userName, String password);
}
###############################################################
public class UserPresenter implements IUserPresenter {

    private Context context;
    private IUserModel userModel;
    private IRequestView requestView;

    public UserPresenter(Context context, IRequestView requestView) {
        this.context = context;
        userModel = new UserModel();
        this.requestView = requestView;
    }

    /**
     * 密码登录
     *
     * @param userName 用户名
     * @param password 密码
     */
    @Override
    public void loginByPassword(String userName, String password) {
        if (TextUtils.isEmpty(userName)) {
            ToastUtil.showShort(context.getApplicationContext(), "用户名不能为空");
            return;
        }
        if (TextUtils.isEmpty(password)) {
            ToastUtil.showShort(context.getApplicationContext(), "密码不能为空");
            return;
        }
        if (userModel != null) {
            userModel.loginByPassword(context, userName, password, requestView);
        }
    }
}

4、View层Activity部分代码

public class LoginActivity extends BaseActivity implements IRequestView {
    ……
    private UserPresenter loginPresenter;

    /**
     * 登录
     */
    private void login() {
        //手机号
        String userName = String.valueOf(loginAccountName.getText());
        //密码
        String password = String.valueOf(loginPassword.getText());
        if (loginPresenter != null) {
            loginPresenter.loginByPassword(userName, password);
        }
    }

    /**
     * 成功
     *
     * @param baseResponse
     */
    @Override
    public void succeed(BaseResponse baseResponse) {
        Object data = baseResponse.getData();
        if (data instanceof UserData) {
            //更新UI、完成其他操作
        }
    }

    /**
     * 失败
     *
     * @param message 错误提示消息
     */
    @Override
    public void failed(String message) {
        ToastUtil.showShort(getApplicationContext(), message);
    }
}

使用了MVP模式之后,我们再回过头来看看登录功能的全部代码,是不是非常简洁,各层分工也非常明确,这样以后维护起来也会事半功倍。


参考链接

https://www.jianshu.com/p/3e981d261e90
https://www.jianshu.com/p/19283a3f61de

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