RxHttp 一条链发送请求,新一代Http请求神器(一)
来源:Android技术干货分享     阅读:489
源码超市
发布于 2019-06-11 02:45
查看主页

简介

RxHttp是基于OkHttp的二次封装,并于RxJava做到无缝衔接,一条链就能发送一个完整的请求。主要功能如下:

gradle依赖

implementation 'com.rxjava.rxhttp:rxhttp:1.0.1'//注解解决器,生成RxHttp类,就可一条链发送请求annotationProcessor 'com.rxjava.rxhttp:rxhttp-compiler:1.0.1'//管理RxJava及生命周期,Activity/Fragment 销毁,自动关闭未完成的请求implementation 'com.rxjava.rxlife:rxlife:1.0.4'

RxHttp 源码 RxLife 源码

初始化

//设置debug模式,此模式下有日志打印HttpSender.setDebug(boolean debug)//非必需,只能初始化一次,第二次将抛出异常HttpSender.init(OkHttpClient okHttpClient)//或者者,调试模式下会有日志输出HttpSender.init(OkHttpClient okHttpClient, boolean debug)

此步骤是非必需的,不初始化或者者传入null即代表使用默认OkHttpClient对象。

疑问:标题不是说好的是RxHttp,这么用HttpSender做少量初始化呢?这里先卖一个关子,后面会解答

设置公共参数

相信大多数开发者在开发中,都遇到要为Http请求增加公共参数/请求头,甚至要为不同类型的请求增加不同的公共参数/请求头,为此,RxHttp为大家提供了一个静态接口回调,如下,每发起一次请求,此接口就会被回调一次,并且此回调在子线程进行(在请求执行线程回调)

HttpSender.setOnParamAssembly(new Function() {    @Override    public Param apply(Param p) {         if (p instanceof GetRequest) {//根据不同请求增加不同参数        } else if (p instanceof PostRequest) {        } else if (p instanceof PutRequest) {        } else if (p instanceof DeleteRequest) {        }        //可以通过 p.getSimpleUrl() 拿到url更改后,重新设置        //p.setUrl("");        return p.add("versionName", "1.0.0")//增加公共参数                .addHeader("deviceType", "android"); //增加公共请求头    }});

而后有些请求我们不希望增加公共参数/请求头,RxHttp又改如何实现呢?很简单,发起请求前,设置不增加公共参数,如下:

Param param = Param.get("http://...")        //设置能否对Param对象修饰,即能否增加公共参数,默认为true        .setAssemblyEnabled(false); //设为false,就不会回调上面的静态接口

到这,也许你们会有疑问,Param 是什么东东,下面就为大家讲解。

Param

首先,我们来看看如何发送一个请求

Param param = Param.get("http://...")        .add("key", "value");Disposable disposable = HttpSender.from(param)        .subscribe(s -> { //这里的s为String类型,即Http请求的返回结果           //成功回调        }, throwable -> {           //失败回调        });

疑问:说好的一条链发送请求呢?别焦急,还没到放大招的时候 到这,我可以告诉大家,Param承担的是一个请求体的一个角色,我们通过Param可以确定请求方式(如:Get、Post、Put、Delete等请求方式)、增加请求参数、增加请求头、增加File对象等;而后通过HttpSender,传入Param对象,将请求发送出去。

HttpSender

到这,有人又有疑问,前面初始化、设置公共参数都用到了HttpSender,这里发送请求又用到了HttpSender ,那么它又是承担怎样样的一个角色呢?看名字,我们可以了解为它就是一个请求发送者,通过一个from操作符,传入一个Param对象,而后返回一个RxJavaObservable对象,此时,我们即可以使用RxJava强大的操作符去解决相关的逻辑(这就是简介说的,做到了与RxJava的无缝链接),在这,我们只是使用了subscribe操作符去订阅观察者。

RxHttp

现在,我们正式放大招,标题说好的一条链发送请求,既然吹嘘了,就要去实现它。拿上面的例子,看看我们如何一条链实现,上代码

  RxHttp.get("http://...")        .add("key", "value")        .from()          .subscribe(s -> { //这里的s为String类型,即Http请求的返回结果           //成功回调        }, throwable -> {           //失败回调        });

我们的主角RxHttp终于登场了,可以看到使用RxHttp类我们就实现了一条链完成请求的发送,那它又是承担一个什么角色呢?我们暂时可以了解为RxHttp=Param+HttpSender,并且还有自己特殊的使命。至于什么使用,后面会讲解。

我们现在来解疑惑,为什么我们的库叫RxHttp,但是初始化、设置公共参数等却用HttpSender?由于RxHttp这个类不在RxHttp库中,它是通过注解解决器生成的类。前面我们看到gradle依赖时,使用了

annotationProcessor 'com.rxjava.rxhttp:rxhttp-compiler:1.0.1'

该注解解决器的目的就是在项目中生成RxHttp类,那为何不直接把它写到库里面去呢?前面讲过,由于它有自己的使命,而这个使命,在RxHttp库里无法完成。

接下来,我们来看看,如何发送Post请求、如何在Activity/Fragment销毁时,自动关闭为完成的请求、如何上传/下载文件及进度的监听、如何把Http返回的结果自动解析成我们想要的对象。

注:以下讲解均使用RxHttp

Post

  RxHttp.postForm("http://...")        .add("key", "value")        .from()          .subscribe(s -> { //这里的s为String类型,即Http请求的返回结果           //成功回调        }, throwable -> {           //失败回调        });

可以看到,跟上面的Get请求只有一点不同,Get是RxHttp.get,而Post是RxHttp.postForm,除此之外,没有任何区别,我们在看来来,RxHttp都有哪些静态方法供我们选择请求方式

可以看到,默认提供了10个静态方法供我们选择具体的请求方式,有Get、Post、Put等,而Post等又分为postForm和postJson,这个好了解,前者是发送表单形式的post请求,后者是发送json字符串的post请求。

现实中,这些默认的请求方式显然不能满足我们的需求,如:我要发送加密的post请求,这个时候该怎样办呢?此时就需要我们自己设置请求方式。

Activity 销毁,自动关闭未完成的请求

上面的案例中,在Activity/Fragment销毁时,假如请求还未完成,就会造成Activity/Fragment 无法回收,导致内存泄漏。这是非常严重的问题,那么RxHttp是如何处理的呢?此时,就要引入我自己写的另一个库RxLife,直接看看如何使用

  RxHttp.postForm("http://...")        .add("key", "value")        .from()        .as(RxLife.as(this)) //订阅观察者前,加上这句话就可        .subscribe(s -> {           //成功回调        }, throwable -> {           //失败回调        });  //或者者  RxHttp.postForm("http://...")        .add("key", "value")        .from()        .as(RxLife.asOnMain(this)) //asOnMain 可以在主线程回调观察者        .subscribe(s -> {           //成功回调        }, throwable -> {           //失败回调        });

这里的thisLifecycleOwner对象,它是一个接口,这里我们传入的是Activity,由于Activity实现了LifecycleOwner接口。当Activity/Fragment销毁时,会将RxJava的管道中断,管道中断时,又会将未完成的请求自动关闭。 在下面的讲解中,我们均会使用RxLife

文件上传/下载及进度监听

使用RxHttp,可以很优雅的实现文件上传/下载及进度的监听,如何优雅?直接上代码

文件上传

  RxHttp.postForm("http://...") //发送Form表单形式的Post请求        .add("key", "value")        .add("file1", new File("xxx/1.png")) //增加file对象        .add("file2", new File("xxx/2.png"))        .from() //from操作符,是异步操作        .as(RxLife.asOnMain(this))  //感知生命周期,并在主线程回调        .subscribe(s -> {             //成功回调        }, throwable -> {            //失败回调        });

可以看到,文件上传跟普通的post请求其实没啥区别,无非就是在post请求的基础上,调用add方法增加要上传的文件对象。

文件下载

  //文件存储路径  String destPath = getExternalCacheDir() + "/" + System.currentTimeMillis() + ".apk";  RxHttp.get("http://update.9158.com/miaolive/Miaolive.apk")        .download(destPath) //注意这里使用download操作符,并传入本地路径        .as(RxLife.asOnMain(this))  //感知生命周期,并在主线程回调        .subscribe(s -> {            //下载成功,回调文件下载路径        }, throwable -> {            //下载失败        });

下载跟普通请求不同的是,下载使用的是download操作符,其它都一样。

文件下载进度监听

//文件存储路径  String destPath = getExternalCacheDir() + "/" + System.currentTimeMillis() + ".apk";  RxHttp.get("http://update.9158.com/miaolive/Miaolive.apk")        .downloadProgress(destPath) //注:假如需要监听下载进度,使用downloadProgress操作符        .observeOn(AndroidSchedulers.mainThread())        .doOnNext(progress -> {            //下载进度回调,0-100,仅在进度有升级时才会回调,最多回调101次,最后一次回调文件存储路径            int currentProgress = progress.getProgress(); //当前进度 0-100            long currentSize = progress.getCurrentSize(); //当前已下载的字节大小            long totalSize = progress.getTotalSize();     //要下载的总字节大小            String filePath = progress.getResult(); //文件存储路径,最后一次回调才有内容        })        .filter(Progress::isCompleted)//下载完成,才继续往下走        .map(Progress::getResult) //到这,说明下载完成,返回下载目标路径        .as(RxLife.as(this)) //感知生命周期        .subscribe(s -> {//s为String类型,这里为文件存储路径            //下载完成,解决相关逻辑        }, throwable -> {            //下载失败,解决相关逻辑        });

下载进度的监听我们略微看一下 ,首先一点,下载使用download操作符,而下载进度监听使用downloadProgress操作符,随后,我们使用了doOnNext操作符解决进度回调,注意这里是仅当有进度升级时,才会回调,其中的progress变量是一个Progress类型的对象,我们贴上源码:

public class Progress<T> {    private int  progress; //当前进度 0-100    private long currentSize;//当前已完成的字节大小    private long totalSize; //总字节大小    private T mResult; //http返回结果,上传/下载完成时调用    //省略get/set方法}

因为进度回调会执行101次(上面注释有解释),而最下面观察者其实是不需要关心这么多事件的,只要要关心最后下载完成的事件,所以使用了filter操作符过滤事件,只需还未下载完成,就将事件过滤调,不让往下走。最终下载完成后,拿到本地下载路径。

文件上传进度监听

  RxHttp.postForm("http://www.......") //发送Form表单形式的Post请求        .add("file1", new File("xxx/1.png"))        .add("file2", new File("xxx/2.png"))        .add("key1", "value1")//增加参数,非必需        .add("key2", "value2")//增加参数,非必需        .addHeader("versionCode", "100") //增加请求头,非必需        .uploadProgress() //注:假如需要监听上传进度,使用uploadProgress操作符        .observeOn(AndroidSchedulers.mainThread()) //主线程回调        .doOnNext(progress -> {            //上传进度回调,0-100,仅在进度有升级时才会回调,最多回调101次,最后一次回调Http执行结果            int currentProgress = progress.getProgress(); //当前进度 0-100            long currentSize = progress.getCurrentSize(); //当前已上传的字节大小            long totalSize = progress.getTotalSize();     //要上传的总字节大小            String result = progress.getResult(); //Http执行结果,最后一次回调才有内容        })        .filter(Progress::isCompleted)//过滤事件,上传完成,才继续往下走        .map(Progress::getResult) //到这,说明上传完成,拿到Http返回结果并继续往下走        .as(RxLife.as(this))  //感知生命周期        .subscribe(s -> { //s为String类型,由SimpleParser类里面的泛型决定的            //上传成功,解决相关逻辑        }, throwable -> {            //上传失败,解决相关逻辑        });

上传进度监听使用downloadProgress操作符,剩下的操作跟下载进度监听的操作都一样,通过doOnNext监听上传进度,而后过滤事件,最终拿到Http的返回结果。

数据解析器Parser

在上面的案例中,观察者拿到数据类型都是String类型,而后现实开发中,我们经常需要对数据解析成我们想要的对象,RxHttp考虑到了这一点,现在我们就来看看如何的到我们想要的对象

我们拿淘宝获取IP的接口作为测试接口http://ip.taobao.com/service/getIpInfo.php?ip=63.223.108.42 对应的数据结构如下

public class Response {    private int     code;    private Address data;    //省略set、get方法    class Address {        //为简单起见,省略了部分字段        private String country; //国家        private String region; //地区        private String city; //城市        //省略set、get方法    }}

开始发送请求

  RxHttp.get("http://ip.taobao.com/service/getIpInfo.php") //Get请求        .add("ip", "63.223.108.42")//增加参数        .addHeader("accept", "*/*") //增加请求头        .addHeader("connection", "Keep-Alive")        .addHeader("user-agent", "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1;SV1)")        .fromSimpleParser(Response.class)  //这里返回Observable<Response> 对象        .as(RxLife.asOnMain(this))  //感知生命周期,并在主线程回调        .subscribe(response -> {            //成功回调        }, throwable -> {            //失败回调        });

可以看到,这里我们没有用from操作符,而是用了fromSimpleParser操作符,并且传入Response.class,最后观察者拿到的response变量就是Response类型的对象。怎样样,是不是很简单。RxHttp为我们提供了一系列的fromXXX方法,我们来看一下:

我们可以看到,少量基本类型的封装对象RxHttp都为我们封装好了,还有一个fromListParser方法,此方法是用来解析集合对象的,少量常见的数据结构,RxHttp都为我们考虑到了,并封装好了,而后,少量不常见的数据呢?眼尖的你也许发现了,上图中还有一个<T> Observable<T> from(Parser<T> parser)方法,它允许我们传入一个自己设置的解析器。

小结

到这,RxHttp的基本用法我们就讲解完毕了,可以看到,使用RxHttp类一条链就能完成一个完整的Http请求,简单一点,就是请求三部曲:

以上所有的案例都离不开这3个步骤。最后,你会发现,RxHttp除了提供的一系列强大的功能外,在写法上,不论什么请求,都极其的类似,只需通过RxHttp类,就能一条链,完成所有的请求,极大的降低了学习成本。

假如你觉得RxHttp+RxLife好用,请记得给我star

RxHttp还是会有它的不足,假如有好的idea,请留言或者者联络我。

针对Android程序员,我这边给大家整理了少量资料,包括不限于高级UI、性能优化、架构师课程、NDK、混合式开发(ReactNative+Weex)微信小程序、Flutter等全方面的Android进阶实践技术;希望能帮助到大家,也节省大家在网上搜索资料的时间来学习,也可以分享动态给身边好友一起学习!

资料领取:点赞+加群免费获取 Android IOC架构设计

加群 Android IOC架构设计领取获取往期Android高级架构资料、源码、笔记、视频。高级UI、性能优化、架构师课程、混合式开发(ReactNative+Weex)全方面的Android进阶实践技术,群内还有技术大牛一起探讨交流处理问题。

免责声明:本文为用户发表,不代表网站立场,仅供参考,不构成引导等用途。 系统环境 服务器应用
相关推荐
首页
搜索
订单
购物车
我的