Android进阶: 详解OkHttp+Retrofit+Rxjava实现网络请求

3,905 阅读8分钟

前言

摘要

网络请求,就是实现客户端(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

环境版本.png

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配合起来使用,其优缺点是什么?

优点:

1:帮助快速实现网咯请求,忽略底层实现细节,让开发者更加聚焦于业务层
2:以接口的形式进行网络请求,更符合java编程规范,同时retrofit将各个框架的精髓柔和在一起,帮助开发者以更优雅的方式解决更复杂的问题

缺点:

1:上手难度较大,对开发者技术要求较高