这一定是最简单的MVP+Retrofit
来源:互联网 发布:怎么在mac上装windows 编辑:程序博客网 时间:2024/06/05 07:15
说明:不讲原理,不讲优化,就是干
目标:学会如何搭建最最基本的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.
*/
public interface LoginContract {
/**
* 与UI相关,与view相关操作
*/
interface View {
// 定义Presenter
void setPresenter();
// 展示等待加载页面
void showLoading();
// 隐藏等待加载页面
void hideLoading();
// 显示登陆信息
void showLoginInfo(String msg);
}
/**
* 与业务相关
*/
interface Presenter {
/**
* 登陆
* @param userId 用户id
* @param userPassword 密码
*/
void login(String userId, String userPassword);
}
}
第二步:
搞一个实现V接口的view类。本例中的view类就是LoginActivity。首先实现接口所有的方法是必须的,然后这里有两个地方需要注意
一,我们是在实现V层接口setPresenter方法里通过LoginPresenter的构造方法将LoginActivity传递过去的(LoginPresenter是P的实现类),这里要记得主动调用一下setPresenter方法触发初始化presenter这个事
二,就是所谓的MVP中V层和P层分隔开,UI和业务分隔开。比如本例登陆按钮的点击事件,他并不是我们平时看到的直接撸网络请求代码,而是调用了P层里的的方法,说人话就是把网络请求一大堆代码封装了一个方法放到了P层那个类里头了,我们在调用的时候传需要用到的参数就行了。你说坑不坑,这点玩意说的那么高大尚
/**
* MVP层中的View层
*/
public class LoginActivity extends AppCompatActivity implements LoginContract.View {
private LoginPresenter mPresenter;
private EditText mEtName, mEtPwd;
private LinearLayout mLayoutLoading;
@Override
protected void onCreate(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(new View.OnClickListener() {// 登陆按钮
@Override
public void onClick(View view) {// 点击登陆不是直接请求网络,而是通过presenter请求网络,然后将请求回来的数据交给view来更新
mPresenter.login(mEtName.getText().toString().trim(), mEtPwd.getText().toString().trim());
}
});
}
@Override
public void setPresenter() {
mPresenter = new LoginPresenter(this);// 一是为了实例化presenter,二是通过构造方法将view实例传递给presenter
}
@Override
public void showLoading() {// 展示遮罩层
mLayoutLoading.setVisibility(View.VISIBLE);
}
@Override
public void hideLoading() {// 隐藏遮罩层
mLayoutLoading.setVisibility(View.GONE);
}
@Override
public void showLoginInfo(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
*/
public class LoginPresenter implements LoginContract.Presenter {
private LoginContract.View mView;
public LoginPresenter(LoginContract.View view) {// 获取到view的实例化对象
this.mView = view;
}
@Override
public void login(String userId, String password) {
mView.showLoading();// 调用view的展示遮罩方法(view用来更新具体的UI)
// 网络请求(可以自己封装一个网络库)
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("http://192.168.1.101:8080/merclienttest/")// 请求的url
.addConverterFactory(GsonConverterFactory.create())// 设置Gson为实体类解析工具
.build();
LoginApi loginApi = retrofit.create(LoginApi.class);// 传入一个接口类并返回此类的实例对象
Call<LoginBean> call = loginApi.login(userId, password);// 调用类中定义的login方法
call.enqueue(new Callback<LoginBean>() {// retrofit异步请求
@Override
public void onResponse(Call<LoginBean> call, Response<LoginBean> response) {
mView.hideLoading();// 调用view的隐藏遮罩方法(view用来更新具体的UI)
mView.showLoginInfo(response.body().getMsg());// 调用view的吐司方法(view用来更新具体的UI)
}
@Override
public void onFailure(Call<LoginBean> 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<LoginBean> login(@Query("userId") String userId, @Query("password") String password); 其中 login 代表自己定义的一个方法,名字随便起(小驼峰式命名),@Query("userId") 代表接口中有个名为 userId 的参数, String userId 代表给这个参数传值,值为userId(名字随便起)
/**
* 登陆接口
* Created by wangjiong on 2017/12/7.
*/
public interface LoginApi {
@GET("login")//get请求login接口(接口名需要后台提供)
Call<LoginBean> login(@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插件自动生成,啥?没听过,你又不是妹子,百度吧
public class LoginBean {
/**
* code : 200
* msg : 登陆成功
*/
private String code;
private String msg;
public String getCode() {
return code;
}
public void setCode(String code) {
this.code = code;
}
public String getMsg() {
return msg;
}
public void setMsg(String msg) {
this.msg = msg;
}
}
第三步,调用Retrofit方法请求网络。做完上面两步,就可以正常调用了,咋用?你又不是妹子,参考LoginPresenter吧
/**
* MVP中的P层
* Created by wangjiong on 2017/12/7
*/
public class LoginPresenter implements LoginContract.Presenter {
private LoginContract.View mView;
public LoginPresenter(LoginContract.View view) {// 获取到view的实例化对象
this.mView = view;
}
@Override
public void login(String userId, String password) {
mView.showLoading();// 调用view的展示遮罩方法(view用来更新具体的UI)
// 网络请求(可以自己封装一个网络库)
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("http://192.168.1.101:8080/merclienttest/")// 请求的url
.addConverterFactory(GsonConverterFactory.create())// 设置Gson为实体类解析工具
.build();
LoginApi loginApi = retrofit.create(LoginApi.class);// 传入一个接口类并返回此类的实例对象
Call<LoginBean> call = loginApi.login(userId, password);// 调用类中定义的login方法
call.enqueue(new Callback<LoginBean>() {// retrofit异步请求
@Override
public void onResponse(Call<LoginBean> call, Response<LoginBean> response) {
mView.hideLoading();// 调用view的隐藏遮罩方法(view用来更新具体的UI)
mView.showLoginInfo(response.body().getMsg());// 调用view的吐司方法(view用来更新具体的UI)
}
@Override
public void onFailure(Call<LoginBean> call, Throwable t) {
mView.hideLoading();
}
});
}
}
源码地址:https://github.com/GodJiong/mvp
- 这一定是最简单的MVP+Retrofit
- 这一定是最简单的自定义布局
- 简单的mvp+retrofit+rxjava示例
- Mvp+Rxandroid+Retrofit的简单实现
- RXJava+Retrofit+MVP的简单封装
- 简单实用的mvp+retrofit+rxjava+dagger2
- MVP+retrofit+rxjava+Knife的简单使用
- MVP&Retrofit&Rxjava&Gson的简单例子
- 简单的mvp+retrofit+rxjava示例
- Android MVP+RxJava+Retrofit 的简单模型
- Retrofit+mvp简单实例
- MVP+Retrofit+RxJava简单事例
- 简单MVP-Retrofit-Rxjava-OKhttp
- MVP+Fresco+Retrofit实现的一个简单的适配器类
- Retrofit网络请求和MVP的简单的讲解
- 一个简单可复用的MVP+RxJava+Retrofit例子
- 简单的MVP+Retrofit+RxJava请求网络数据(一)
- MVP+RXJAVA+Retrofit+Fresco实现简单的效果
- 浅析JBPM工作流引擎
- 2017 12.29的c语言编程作业
- SDUSTOJ
- [jzoj]3541. 【清华集训2014】破冰派对(组合数+思维)
- 设计模式-工厂方法模式
- 这一定是最简单的MVP+Retrofit
- ffmpeg视音频同步
- 717. 1-bit and 2-bit Characters
- 嵌入式软件学习路线图!
- Mask-RCNN技术解析
- 《剑指offer》刷题笔记(时间空间效率的平衡):两个链表的第一个公共结点
- Java线程间通信的同步问题、wait/notify使用
- 565. Array Nesting
- Mysql LINUX使用