前言
摘要
网络请求,就是实现客户端(app)与服务端(存放数据的地方)之间的数据传递,基本是现在每个APP必备的功能,所有网络相关的逻辑,都贯穿整个APP,网络相关的框架稳定性,易用性,封装的好坏,直接影响到项目的质量;由于技术发展的成熟,使用流行的第三方框架就能快速实现网络请求。
本文主要为进阶知识,通过OkHttp+Retrofit+RxAndroid实现一个网络请求,同时给出入门学习方法。
三方框架介绍+学习方法
我们整个网络请求划分为网络底层请求(真正实现网络请求的细节)、网络上层请求(简易触发底层进行请求的方法)、结果解析、以及响应式编程(简化涉及网络的业务流程),学习方法当然是先掌握基础知识,懂得基本使用,再配合使用以达到融汇贯通
1、OkHttp(网络底层框架)
一个处理底层网络请求的开源项目,是安卓端最火热的轻量级框架,由移动支付Square公司贡献(该公司还贡献了Picasso)
用于替代HttpUrlConnection和Apache HttpClient(android API23 6.0里已移除HttpClient,现在已经打不出来)
基础学习地址: www.jianshu.com/p/da4a806e5…
2、Retrofit(网络上层框架)
将HTTP API转化成Java接口形式的框架。虽然Okhttp已经做了大量的底层封装,方便我们调用,但每次请求都需要写大量繁琐且重复的请求逻辑,Retrofit就是为了进一步简化该过程而存在的产物
基础学习地址: cloud.tencent.com/developer/a…
3、RxAndorid(响应式编程框架)
函数响应式编程=函数式编程思路+响应式编程(根据响应的事件,触发下一个事件的发生)。它的作用为极大地简化项目,特别是处理嵌套回调的异步事件、复杂的列表过滤和变换以及处理时间相关的等问题,RxAndorid实现了Android上特有的响应式编程,类似且区分于Rxjava。
4、Json解析框架(结果解析)
如果说1、2、3步是过程,那么4就是对结果的处理,这里我们使用Google的Gon进行结果解析(就是将从网络中传递过来的xml数据变成我们希望的数据格式,以便在编码过程中加工传递)
实现流程
基本知道他们是什么东西之后,就来着重看他们说怎么配合起来使用的
1、配置网络请求地址
既然我们是要实现网络请求,总要有个请求地址吧?(请求简单来说就是到对应服务器拿相应数据)
配置方法
用Android Studio项目提供的productFlavors(产品风味)功能实现,它可以方便我们配置、切换各种环境,如开发、测试、正式、预上线等,同时还可以实现渠道包。
渠道包指带有各自应用市场标识的相应apk,使用它是为了方便在各应用市场统计下载量等特定数据
流程如下:
1)在app/build.gradle的android方法中添加如下代码:
// 配置不同的环境
productFlavors{
// 开发环境,ENDPOINT指数据地址,这里我使用的是某快递的API
dev {
// API端点
```
buildConfigField('String', "ENDPOINT", '"http://www.kuaidi100.com/query?type=快递公司代号&postid=快递单号"')
dimension = minSdkVersion
}
// 正式环境
prod {
// API端点
buildConfigField 'String','ENDPOINT','"http://www.kuaidi100.com/query?type=快递公司代号&postid=快递单号"'
dimension = minSdkVersion
}
}
2)rebuild
rebuild之后可以在Build Varians中任意切换地址,现在我们选中的是开发环境:dev
3)配置网络地址常量
/**
* 常量类
*/
public class Constant {
public static final String ENDPOINT = BuildConfig.ENDPOINT;
}
####注意: 这样配置的优点在于,每当我们从Build Varians切换环境时,Constant类中的ENDPOINT字段就会自动更换为对应环境地址,不用我们每次去修改环境地址(其他环境相关信息也一样,大家感兴趣可以仔细研究productFlavors),提升了开发效率
2、添加依赖
//okhttp
implementation 'com.squareup.okhttp3:okhttp:4.2.0'
//retrofit
implementation 'com.squareup.retrofit2:retrofit:2.6.2'
//使用gson解析json
implementation 'com.google.code.gson:gson:2.8.5'
//适配retrofit使用gson解析
//版本要和retrofit一样
implementation 'com.squareup.retrofit2:converter-gson:2.6.2'
//适配retrofit支持rxjava
implementation 'com.squareup.retrofit2:adapter-rxjava2:2.6.2'
// RxAndroid
implementation 'io.reactivex.rxjava2:rxandroid:2.1.1'
### 3、代码实现
#### 第一步:创建接收数据的实体类
从网络中请求的数据,我们总得有个地方接受数据,接收数据的地方我们就叫做数据实体类
数据实体的格式取决于网络返回的数据格式,下图为发起请求后的数据格式:(直接以拿到错误信息为例)
![数据格式.png](https://p9-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/acd5fa57b4444da5b065dcc54115bb75~tplv-k3u1fbpfcp-watermark.image?)
上图可知,返回的为标准的Json格式,所以我们创建实体类也与相应字段一一对应即可:
```java
public class Delivery {
private String message;
private String nu;
private String ischeck;
private String condition;
private String com;
private String status;
private String state;
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
public String getNu() {
return nu;
}
public void setNu(String nu) {
this.nu = nu;
}
public String getIscheck() {
return ischeck;
}
public void setIscheck(String ischeck) {
this.ischeck = ischeck;
}
public String getCondition() {
return condition;
}
public void setCondition(String condition) {
this.condition = condition;
}
public String getCom() {
return com;
}
public void setCom(String com) {
this.com = com;
}
public String getStatus() {
return status;
}
public void setStatus(String status) {
this.status = status;
}
public String getState() {
return state;
}
public void setState(String state) {
this.state = state;
}
}
第二步:创建网络请求接口
我们知道,过往的网络请求需要写一堆的配置代码才能发起请求,是不是非常麻烦?这时候retrofit的出现,可谓解放了大家,它将复杂请求的代码变为使用接口形式进行请求(可理解为对复杂的逻辑进行了封装,只向上暴露简约的接口),简单且清晰
public interface Request {
// retrofit:以接口形式进行网络请求
// Delivery用于接收结果,就是我们刚刚创建的实体类
@GET("")
Observable<Delivery> delivery();
}
第三步:初始化请求配置
// 底层具体请求的实现交给okhttp(虽然retrofit底层就是用的okhttp,但是这里单独配置,可以便于我们自定义拦截器。关于拦截器,这里不作深入探讨)
OkHttpClient.Builder builder = new OkHttpClient.Builder();
// 创建一个retrofit
Retrofit retrofit = new Retrofit.Builder()
.client(builder.build())
// 设置基址
.baseUrl(Constant.ENDPOINT)
// 适配rxjava,目的在于使用观察者模式,分解上层请求的过程,便于我们横加干预(比如请求嵌套)
.addCallAdapterFactory(RxJava2CallAdapterFactory.create())
// 使用Gson框架解析请求返回的结果,因为返回的是xml,只有解析过后,才能将数据变为对象,放置到我们刚刚创建你的实体类当中,便于数据的传递使用
.addConverterFactory(GsonConverterFactory.create())
.build();
// 创建一个request
Request request = retrofit.create(Request.class);
第四步:发起请求
request.delivery()
// 在子线程中发起请求
.subscribeOn(Schedulers.io())
// 主线程中处理结果,因为往往需要更新UX
.observeOn(AndroidSchedulers.mainThread())
// 观察者模式开启订阅,以接收“发送请求”这个事件返回的结果
.subscribe(new Observer<Delivery>() {
@Override
public void onSubscribe(Disposable d) {
}
@Override
public void onNext(Delivery delivery) {
// 请求成功回调,得到结果数据delivery
}
@Override
public void onError(Throwable e) {
// 请求失败回调,报异常e
}
@Override
public void onComplete() {
// 请求结束回调
}
});
高阶用法
用法一:嵌套请求
第一步:定义第一次、第二次请求的接口
Observable<Delevery1> observable1;
Observable<Delevery2> observable2;
第二步:采用Observable<...>形式 对2个网络请求 进行封装
observable1 = request.delivery1();
observable2 = request.delivery2();
第三步:使用变换操作符FlatMap进行嵌套请求
FlatMap:将被观察者发送的事件序列进行拆分 & 单独转换,再合并成一个新的事件序列,最后再进行发送
// (初始被观察者)切换到IO线程进行网络请求1
observable1.subscribeOn(Schedulers.io())
// (新观察者)切换到主线程 处理网络请求1的结果
.observeOn(AndroidSchedulers.mainThread())
.doOnNext(new Consumer<Delivery1>(){
@Override
public void accept(Delivery1 result)throws Exception{
Log.d(TAG,"第1次网络请求成功");
result.show();
// 对第1次网络请求返回的结果进行操作
}
})
.observeOn(Schedulers.io())
// 因为flatMap是对初始被观察者作变换,所以对于旧被观察者,它是新观察者,所以需要observeOn切换线程
// 但对于初始观察者,它则是新的被观察者
// 作变换,即在新的线程中,将原始事件(请求1)变成新事件(请求2)
.flatMap(new Function<Delivery1, ObservableSource<Delivery2>>(){
@Override
public ObservableSource<Delivery2> apply(Delivery1 result)throws Exception{
// 将网络请求1转换成网络请求2,即发送网络请求2
return observable2;
}
})
// (初始观察者)切换到主线程 处理网络请求2的结果
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Consumer<Delivery2>(){
@Override
public void accept(Delivery2 result)throws Exception{
Log.d(TAG,"第2次网络请求成功");
result.show();
// 对第2次网络请求返回的结果进行操作
}
},new Consumer<Throwable>(){
@Override
public void accept(Throwable throwable)throws Exception{
}
});
}
技术栈分析
问题:
将okhttp、retrofit、rxjava、gson配合起来使用,其优缺点是什么?