这一定是最简单的MVP+Retrofit

说明:不讲原理,不讲优化,就是干

目标:学会如何搭建最最基本的mvp架构

简介

我承认画图不是我的强项

MVP是MVC衍生出来的架构,现在也比较成熟了,用的人也多了,面试也会考了,所以你必须要知道了

M:数据层(数据库,文件,网络等)

V:UI层(Activity,Fragment,View及其子类,Adapter及其子类)

P:中介(作用:关联V和M)

经过思想斗争,我觉得理论上的东西解释再多不如代码敲一遍,下面用一个用户登陆功能讲解如何搭建MVP架构,顺便简单用下Retrofit网络请求库(别怕都有注释)总之,MVP记住一个核心思想:V层就只做UI的操作,所有的业务处理和数据处理都交给P层(不然要你何用)就相当于把Activity里你写的众多网络请求和数据处理代码统统提取封装到P里了

MVP结构

api:Retrofit专用的,就两行代码,和mvp无关,待会给你看

bean:登陆的实体类,和mvp无关

login:可以看出是按功能分包。他比平时见到的多出来两个类,一个是 LoginPresenter(P层),一个是 LoginContract(契约接口类,用于将P和V接口封装到一起)他们是mvp重要的组成部分

架构图如下:

思路

mvp结构实现分三步:

一,搞一个接口契约类Contract,内含V接口和P接口

二,搞一个实现V接口的view类

三,搞一个实现P接口的presenter类

第一步:

搞一个接口契约类Contract,内含V接口和P接口。V接口里面放的是UI更新方法(V接口的实现类用到的方法);P接口里面放的是网络请求,数据读取,文件读取等具体的业务操作方法(P接口的实现类用到的方法)

从动态图可以看到,一共有三个地方有UI界面变化

①点击登陆展示等待加载遮罩

②登陆成功或者失败后取消等待加载遮罩

③取消等待加载遮罩的同时吐司

所以V接口里会有三个UI更新方法,那么就在V接口写三个方法呗,值得注意的是setPresenter方法只是用来把V层和P层关联的,本身与UI更新无关,但是必须要有的

P接口在本例中只需要实现一个登陆按钮触发的网络请求就可以啦,所以只有一个方法

由此可见,契约类Contract把V和P接口封装在了一块,而V和P接口又把具体的view和presenter用到的方法封装在了一块

/**

* 包含View和Presenter的契约接口

* Created by wangjiong on 2017/12/7.

*/

publicinterfaceLoginContract{

/**

* 与UI相关,与view相关操作

*/

interfaceView{

// 定义Presenter

voidsetPresenter();

// 展示等待加载页面

voidshowLoading();

// 隐藏等待加载页面

voidhideLoading();

// 显示登陆信息

voidshowLoginInfo(String msg);

}

/**

* 与业务相关

*/

interfacePresenter{

/**

* 登陆

* @param userId      用户id

* @param userPassword 密码

*/

voidlogin(String userId, String userPassword);

}

}

第二步:

搞一个实现V接口的view类。本例中的view类就是LoginActivity。首先实现接口所有的方法是必须的,然后这里有两个地方需要注意

一,我们是在实现V层接口setPresenter方法里通过LoginPresenter的构造方法将LoginActivity传递过去的(LoginPresenter是P的实现类),这里要记得主动调用一下setPresenter方法触发初始化presenter这个事

二,就是所谓的MVP中V层和P层分隔开,UI和业务分隔开。比如本例登陆按钮的点击事件,他并不是我们平时看到的直接撸网络请求代码,而是调用了P层里的的方法,说人话就是把网络请求一大堆代码封装了一个方法放到了P层那个类里头了,我们在调用的时候传需要用到的参数就行了。你说坑不坑,这点玩意说的那么高大尚

/**

* MVP层中的View层

*/

publicclassLoginActivityextendsAppCompatActivityimplementsLoginContract.View{

privateLoginPresenter mPresenter;

privateEditText mEtName, mEtPwd;

privateLinearLayout mLayoutLoading;

@Override

protectedvoidonCreate(Bundle savedInstanceState){

super.onCreate(savedInstanceState);

setContentView(R.layout.activity_login);

setPresenter();// 初始化presenter(很重要!不能说重写就不管了,一定要在view初始化调用此方法)

mEtName = findViewById(R.id.et_name);// 用户名

mEtPwd = findViewById(R.id.et_pwd);// 密码

mLayoutLoading = findViewById(R.id.layout_loading);// 遮罩层

findViewById(R.id.btn_login).setOnClickListener(newView.OnClickListener() {// 登陆按钮

@Override

publicvoidonClick(View view){// 点击登陆不是直接请求网络,而是通过presenter请求网络,然后将请求回来的数据交给view来更新

mPresenter.login(mEtName.getText().toString().trim(), mEtPwd.getText().toString().trim());

}

});

}

@Override

publicvoidsetPresenter(){

mPresenter =newLoginPresenter(this);// 一是为了实例化presenter,二是通过构造方法将view实例传递给presenter

}

@Override

publicvoidshowLoading(){// 展示遮罩层

mLayoutLoading.setVisibility(View.VISIBLE);

}

@Override

publicvoidhideLoading(){// 隐藏遮罩层

mLayoutLoading.setVisibility(View.GONE);

}

@Override

publicvoidshowLoginInfo(String msg){// 吐司登陆信息

Toast.makeText(this, msg, Toast.LENGTH_SHORT).show();

}

}

第三步:

搞一个实现P接口的presenter类。本例中presenter类就是LoginPresenter,可以看到他就一个构造方法(用来关联V层并获取view实例化对象)和一个请求网络数据的方法。高能预警:网络请求前UI页面需要展示一个遮罩层,所以调用了view的showLoading方法,请求结束后UI页面需要取消遮罩并吐司,所以调用了view的hideLoading方法和showLoginInfo方法

/**

* MVP中的P层

* Created by wangjiong on 2017/12/7

*/

publicclassLoginPresenterimplementsLoginContract.Presenter{

privateLoginContract.View mView;

publicLoginPresenter(LoginContract.View view){// 获取到view的实例化对象

this.mView = view;

}

@Override

publicvoidlogin(String userId, String password){

mView.showLoading();// 调用view的展示遮罩方法(view用来更新具体的UI)

// 网络请求(可以自己封装一个网络库)

Retrofit retrofit =newRetrofit.Builder()

.baseUrl("http://192.168.1.101:8080/merclienttest/")// 请求的url

.addConverterFactory(GsonConverterFactory.create())// 设置Gson为实体类解析工具

.build();

LoginApi loginApi = retrofit.create(LoginApi.class);// 传入一个接口类并返回此类的实例对象

Call call = loginApi.login(userId, password);// 调用类中定义的login方法

call.enqueue(newCallback() {// retrofit异步请求

@Override

publicvoidonResponse(Call call, Response response){

mView.hideLoading();// 调用view的隐藏遮罩方法(view用来更新具体的UI)

mView.showLoginInfo(response.body().getMsg());// 调用view的吐司方法(view用来更新具体的UI)

}

@Override

publicvoidonFailure(Call call, Throwable t){

mView.hideLoading();

}

});

}

}

全剧终

妈个鸡这是啥玩意?完了?哈哈哈,没错这就是MVP。就是这么简单。只需要记住一个核心思想V层仅仅是处理UI页面的(只管化妆接客,拉皮条找老鸨子P),业务逻辑放在P层去处理(网络请求,数据库,文件等),P处理完之后再调用一下V层已经写好的对应更新UI的方法即可

扩展

没忘记Retrofit哦,简单介绍下使用方法

分三步:

一,搞一个接口类Api

二,搞一个对应的实体类bean

三,调用Retrofit方法请求网络

第一步:搞一个Api接口。本例中是LoginApi

第一行代码 @GET("login") 这个Get就代表get请求,如果换成Post那就代表post请求。login代表接口名(接口名需要后台提供)

第二行代码 Call login(@Query("userId") String userId, @Query("password") String password); 其中 login 代表自己定义的一个方法,名字随便起(小驼峰式命名),@Query("userId") 代表接口中有个名为 userId 的参数, String userId 代表给这个参数传值,值为userId(名字随便起)

/**

* 登陆接口

* Created by wangjiong on 2017/12/7.

*/

publicinterfaceLoginApi{

@GET("login")//get请求login接口(接口名需要后台提供)

Calllogin(@Query("userId") String userId, @Query("password") String password);// 声明一个login的方法(随便写),两个string形参,并返回一个实体类LoginBean

}

没反应过来?

jsonObject.put("userId",userId) 这样写懂了吧,第一个userId是接口里的参数名,第二个userId是你传的字符串值,名字随便搞的,叫啥都行

你也可以@Query("userId") String myUserId这就等价于

jsonObject.put("userId",myUserId  )  这里只是为了说明问题,所以不必太在意细节

第二步,搞一个对应的实体类bean。这个对应本例中的LoginBean。推荐用GsonFormat插件自动生成,啥?没听过,你又不是妹子,百度吧

publicclassLoginBean{

/**

* code : 200

* msg : 登陆成功

*/

privateString code;

privateString msg;

publicStringgetCode(){

returncode;

}

publicvoidsetCode(String code){

this.code = code;

}

publicStringgetMsg(){

returnmsg;

}

publicvoidsetMsg(String msg){

this.msg = msg;

}

}

第三步,调用Retrofit方法请求网络。做完上面两步,就可以正常调用了,咋用?你又不是妹子,参考LoginPresenter吧

/**

* MVP中的P层

* Created by wangjiong on 2017/12/7

*/

publicclassLoginPresenterimplementsLoginContract.Presenter{

privateLoginContract.View mView;

publicLoginPresenter(LoginContract.View view){// 获取到view的实例化对象

this.mView = view;

}

@Override

publicvoidlogin(String userId, String password){

mView.showLoading();// 调用view的展示遮罩方法(view用来更新具体的UI)

// 网络请求(可以自己封装一个网络库)

Retrofit retrofit =newRetrofit.Builder()

.baseUrl("http://192.168.1.101:8080/merclienttest/")// 请求的url

.addConverterFactory(GsonConverterFactory.create())// 设置Gson为实体类解析工具

.build();

LoginApi loginApi = retrofit.create(LoginApi.class);// 传入一个接口类并返回此类的实例对象

Call call = loginApi.login(userId, password);// 调用类中定义的login方法

call.enqueue(newCallback() {// retrofit异步请求

@Override

publicvoidonResponse(Call call, Response response){

mView.hideLoading();// 调用view的隐藏遮罩方法(view用来更新具体的UI)

mView.showLoginInfo(response.body().getMsg());// 调用view的吐司方法(view用来更新具体的UI)

}

@Override

publicvoidonFailure(Call call, Throwable t){

mView.hideLoading();

}

});

}

}

源码地址:https://github.com/GodJiong/mvp

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

推荐阅读更多精彩内容