MVP google官方demo比较分析

15年年底本人公司新开的一个项目,用上了mvp模式开发,那个时候还没发现google出了mvp的demo。

首先什么是MVP:

  • M-model,即javaBean 数据模型层;
  • V-view,视图层,常用的即Activity Fragment,这里是定义一个接口IView,Activity去实现IView的写法;
  • P-presenter,数据处理层,所有的数据逻辑,业务逻辑都在这里处理;

原来我的写法

而当时我在写mvp时只是简单的写成了:以下几个类:
  • UserInfoModel-model;
  • IUserInfoView-IView;
  • UserInfoActivity-Activity;
  • UserInfoPresenter-Presenter;
接下来假设业务是这样的:网络请求用户信息接口,并将用户信息展现在UserInfoActivity中。
  • 先看目录结构:


    目录.png
  • 1:先看Model--UserInfoModel

public class UserInfoModel {
    private String name;
    private int age;
    private String address;
    public UserInfoModel(String name, int age, String address) {
        this.name = name;
        this.age = age;
        this.address = address;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public int getAge() {
        return age;
    }
    public void setAge(int age) {
        this.age = age;
    }
    public String getAddress() {
        return address;
    }
    public void setAddress(String address) {
        this.address = address;
    }
}
  • 2:View--实现的IUserInfoView:
public interface IUserInfoView {   
          String loadUserId();//假设接口请求需要一个userId
          void showLoading();//展示加载框
          void dismissLoading();//取消加载框展示
          void showUserInfo(UserInfoModel userInfoModel);//将网络请求得到的用户信息回调
}

网络接口请求用户信息之前 获得userId,然后展示loading,数据加载成功取消loading,最后将数据展示在Activity上

  • 3:Presetner--UserInfoPresenter:这里就实现一个模拟的接口请求
public class UserInfoPresenter {
    private IUserInfoView iUserInfoView;

    public UserInfoPresenter(IUserInfoView iUserInfoView) {
        this.iUserInfoView = iUserInfoView;
    }

    public void loadUserInfo() {
        String userId = iUserInfoView.loadUserId();
        iUserInfoView.showLoading();//接口请求前显示loading
        //这里模拟接口请求回调-
        new Handler().postDelayed(new Runnable() {
            @Override
            public void run() {
                //模拟接口返回的json,并转换为javaBean
                UserInfoModel userInfoModel = new UserInfoModel("小宝", 1, "杭州");
                iUserInfoView.showUserInfo(userInfoModel);
                iUserInfoView.dismissloading();
            }
        }, 3000);
    }
}
  • 4:View--UserInfoActivity实现IUserInfoView接口:
public class UserInfoActivity extends AppCompatActivity implements IUserInfoView {
    private TextView tv_name;
    private TextView tv_age;
    private TextView tv_address;
    private UserInfoPresenter presenter;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        tv_name = (TextView) findViewById(R.id.tv_name);
        tv_age = (TextView) findViewById(R.id.tv_age);
        tv_address = (TextView) findViewById(R.id.tv_address);
        presenter = new UserInfoPresenter(this);
        presenter.loadUserInfo();
    }

    @Override
    public void showLoading() {
        Toast.makeText(this, "正在加载", Toast.LENGTH_LONG).show();
    }

    @Override
    public void dismissLoading() {
        Toast.makeText(this, "加载完成", Toast.LENGTH_LONG).show();
    }

    @Override
    public void showUserInfo(UserInfoModel userInfoModel) {
        if (userInfoModel != null) {
            tv_name.setText(userInfoModel.getName());
            tv_age.setText(String.valueOf(userInfoModel.getAge()));
            tv_address.setText(userInfoModel.getAddress());
        }
    }

    @Override
    public String loadUserId() {
        return "1000";//假设需要查询的用户信息的userId是1000
    }
}

这样写并没有错,只是不能更直观的看到IView中的方法和Presenter中的方法的关联。

Google demo写法有所不同:google官方mvp写法demo

下面用google官方demo的写法实现上面的模拟业务:
  • 首先看下目录结构:

google demo mvp 目录.png

这里多了一个contract包:里面放的是契约接口。更能直接明了的看到View和Presenter之间的方法。
还多了一个BaseView,BasePresenter:看代码

public interface BasePresenter {
    void start();
}

这里的start()方法就相当于约定了所有的Presenter的初始化操作都放在start()方法中;

public interface BaseView<T> {
    void setPresenter(T presenter);
}
  • 再来看契约类:UserInfoContract
public interface UserInfoContract {
    interface View extends BaseView<Presenter>{
        void showLoading();//展示加载框
        void dismissLoading();//取消加载框展示
        void showUserInfo(UserInfoModel userInfoModel);//将网络请求得到的用户信息回调
        String loadUserId();//假设接口请求需要一个userId
    }
    interface Presenter extends BasePresenter {
        void loadUserInfo();
    }
}

契约内部有2个接口,分别继承了BaseView和BasePresenter,View和Presenter中实现的方法分别是UI操作,和数据业务逻辑操作,此时是不是看的异常的清晰。

多了一个契约类,契约内部包含了2个接口,一个是Presenter一个是View,就相当于之前的写法中的接口IView和普通类Presenter,只不过现在都将这两个类所需要的业务和UI层的接口直接放在一起展现出来,变得很清晰。在契约接口中的Presenter是一个接口,需要我们去实现,代码如下:

public class UserInfoPresenter implements UserInfoContract.Presenter {
    private UserInfoContract.View view;

    public UserInfoPresenter(UserInfoContract.View view) {
        this.view = view;
        view.setPresenter(this);
    }

    @Override
    public void loadUserInfo() {
        String userId = view.loadUserId();
        view.showLoading();//接口请求前显示loading
        //这里模拟接口请求回调-
        new Handler().postDelayed(new Runnable() {
            @Override
            public void run() {
                //模拟接口返回的json,并转换为javaBean
                UserInfoModel userInfoModel = new UserInfoModel("小宝", 1, "杭州");
                view.showUserInfo(userInfoModel);
                view.dismissLoading();
            }
        }, 3000);
    }

    @Override
    public void start() {
        loadUserInfo();
    }
}

1:UserInfoPresenter 构造函数中传入UserInfoContract.View,并且调用view的setPresenter()方法;
2:将所有的初始化操作都放在start()方法中(这里demo只有一个:网络请求获取用户信息),这样只要进入界面的时候调用start()方法就可以执行一系列初始化的操作,这就相当于一种约定好的开发。

  • 最后看UserInfoActivity如何进行调用
public class UserInfoActivity extends AppCompatActivity implements UserInfoContract.View {
    private TextView tv_name;
    private TextView tv_age;
    private TextView tv_address;

    private UserInfoContract.Presenter presenter;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        tv_name = (TextView) findViewById(R.id.tv_name);
        tv_age = (TextView) findViewById(R.id.tv_age);
        tv_address = (TextView) findViewById(R.id.tv_address);

        new UserInfoPresenter(this);
        presenter.start();
    }

    @Override
    public void showLoading() {
        Toast.makeText(this, "正在加载", Toast.LENGTH_LONG).show();
    }

    @Override
    public void dismissLoading() {
        Toast.makeText(this, "加载完成", Toast.LENGTH_LONG).show();
    }

    @Override
    public void showUserInfo(UserInfoModel userInfoModel) {
        if (userInfoModel != null) {
            tv_name.setText(userInfoModel.getName());
            tv_age.setText(String.valueOf(userInfoModel.getAge()));
            tv_address.setText(userInfoModel.getAddress());
        }
    }

    @Override
    public String loadUserId() {
        return "1000";//假设需要查询的用户信息的userId是1000
    }

    @Override
    public void setPresenter(UserInfoContract.Presenter presenter) {
        this.presenter = presenter;
    }
}

在onCreate()方法:

new UserInfoPresenter(this);
presenter.start();

而并没有写成

presenter=new UserInfoPresenter(this);

因为UserInfoActivity实现了UserInfoContract.View中的setPresenter()方法;而UserInfoPresenter 构造函数中已经调用了UserInfoContract.View中的setPresenter()方法;

两者思想一样,只是写法不同。
后者demo地址

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

推荐阅读更多精彩内容