RxHttp 让你眼前一亮的Http请求框架

RxHttp 完美适配Android 10/11 上传/下载/进度监听 1、前言 随着Android 11的正式发布,适配Android 10/11 分区存储就更加的迫切了,因为Android 11开始,将强制开启分区存储,我们就无法再以绝对路径的方式去读写非沙盒目录下的文件,为此,RxHttp 在2.4.0版本中就正式适配了分区存储,并且,可以非常优雅的实现文件上传/下载/进度监听,三步即可搞懂任意请求。 老规矩,先看看请求三部曲 如果你想了解RxHttp更过功能,请查看以下系列文章 RxHttp 2000+star,协程请求,仅需三步 RxHttp 让你眼前一亮的Http 阅读详情

1

前言

 

RxHttp在今年4月份一经推出,就受到了广大Android 开发者的喜爱,截止本文发表在github上已有800+star,为此,我自己也建个RxHttp&RxLife 的群(群号:290611780)

 

 

 

目前群里也有将近120号人,里面有不少小伙伴提了很多有价值的创意,才使得RxHttp一直坚持走到了现在,在此,感谢大家的喜爱。

 

这期间,一直有人问我,retrofit不香吗?

 

之前不知道该如何回答这个问题,现在我想说,香!!retrofit无疑是目前综合得分最高的选手,但它也有它的不足。

 

RxHttp相较于retrofit,功能上,两者均能实现,并无多大差异,更多的差异体现功能的使用上,也就是易用性,如对文件上传/下载/进度监听的操作上,RxHttp用及简的API,可以说碾压retrofit;

 

另外在baseUrl、公共参数/请求头、请求加解密等功能上的易用性都要优于retrofit;然而这些,个人觉得都不算什么,个人觉得RxHttp最大的优势在于它近乎为0的上手成本、及简的API以及高扩展性,看完这篇文章,相信你会有同感。

 

那RxHttp就没有缺点吗?

 

有,那就是它的稳定性目前还不如retrofit,毕竟RxHttp刚出道8个月,且全部是我一个人在维护,当然,并不是说RxHttp不稳定,RxHttp未开源前,在我司的项目已经使用了近2年,接着今年4月份将其开源,至今大大小小已迭代20多个版本,目前用的人也不在少数,可以说很稳定了。

 

2

 简介

 

RxHttp是基于OkHttp的二次封装,并与RxJava做到无缝衔接,一条链就能发送任意请求。主要优势如下:

 

1. 支持Gson、Xml、ProtoBuf、FastJson等第三方数据解析工具

2. 支持Get、Post、Put、Delete等任意请求方式,可自定义请求方式

3. 支持在Activity/Fragment/View/ViewModel/任意类中,自动关闭请求

4. 支持统一加解密,且可对单个请求设置是否加解密

5. 支持添加公共参数/头部,且可对单个请求设置是否添加公共参数/头部

6. 优雅的实现文件上传/下载及进度的监听,且支持断点下载

7. 优雅的对错误统一处理,且不打破Lambda表达式

8. 优雅的处理多个BaseUrl及动态BaseUrl

9. 30秒即可上手,学习成本极低

 

gradle依赖

 


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

//非必须 根据自己需求选择Converter  RxHttp默认内置了GsonConverter
implementation 'com.rxjava.rxhttp:converter-jackson:1.3.4'
implementation 'com.rxjava.rxhttp:converter-fastjson:1.3.4'
implementation 'com.rxjava.rxhttp:converter-protobuf:1.3.4'
implementation 'com.rxjava.rxhttp:converter-simplexml:1.3.4'

 

注:kotlin用户,请使用kapt替代annotationProcessor

 

3

  使用

 

3.1、准备工作

 

RxHttp 要求项目使用Java 8,请在 app 的 build.gradle 文件中添加以下代码

 


 
compileOptions {
    sourceCompatibility JavaVersion.VERSION_1_8
    targetCompatibility JavaVersion.VERSION_1_8
}

 

 

此时,再Rebuild一下项目(通过Rebuild生成RxHttp类),就可以开始RxHttp的入坑之旅

 

3.2、配置默认的BaseUrl

 

通过@DefaultDomain注解配置默认域名,如下:

 


 
public class Url {
    @DefaultDomain //设置为默认域名
    public static String baseUrl = "https://www.wanandroid.com/";
}

 

 

此步骤是非必须的,这里先介绍@DefaultDomain注解的用法,更多有关域名的介绍,请查看本文3.6章节----多域名/动态域名

 

3.3、请求三部曲

 

先来看看如何发送一个最简单的请求,如下

 


 
RxHttp.get("http://...")  //第一步, 通过get、postXxx、putXxx等方法,确定请求类型         
    .asString()           //第二步, 通过asXxx系列方法,确定返回数据类型    
    .subscribe(s -> {     //第三步, 订阅回调(此步骤同RxJava订阅观察者)
        //请求成功                                         
    }, throwable -> {                                  
        //请求失败                                         
    });                                                

 

是的,不用怀疑,就是这么简单,重要的事情说3遍

 

任意请求,任意返回数据类型,皆遵循请求三部曲

任意请求,任意返回数据类型,皆遵循请求三部曲

任意请求,任意返回数据类型,皆遵循请求三部曲

 

到这,你已经掌握了RxHttp的精髓,我们只需牢记请求三部曲,使用RxHttp就会得心应手。

 

3.3.1、第一部曲:确定请求类型

 

RxHttp内部共提供了14个请求方法,如下:

 


 
RxHttp.get(String)              //get请求    参数拼接在url后面
RxHttp.head(String)             //head请求   参数拼接在url后面
RxHttp.postForm(String)         //post请求   参数以{application/x-www-form-urlencoded}形式提交
RxHttp.postJson(String)         //post请求   参数以{application/json; charset=utf-8}形式提交,发送Json对象
RxHttp.postJsonArray(String)    //post请求   参数以{application/json; charset=utf-8}形式提交,发送Json数组
RxHttp.putForm(String)          //put请求    参数以{application/x-www-form-urlencoded}形式提交
RxHttp.putJson(String)          //put请求    参数以{application/json; charset=utf-8}形式提交,发送Json对象
RxHttp.putJsonArray(String)     //put请求    参数以{application/json; charset=utf-8}形式提交,发送Json数组
RxHttp.patchForm(String)        //patch请求  参数以{application/x-www-form-urlencoded}形式提交
RxHttp.patchJson(String)        //patch请求  参数以{application/json; charset=utf-8}形式提交,发送Json对象
RxHttp.patchJsonArray(String)   //patch请求  参数以{application/json; charset=utf-8}形式提交,发送Json数组
RxHttp.deleteForm(String)       //delete请求 参数以{application/x-www-form-urlencoded}形式提交
RxHttp.deleteJson(String)       //delete请求 参数以{application/json; charset=utf-8}形式提交,发送Json对象
RxHttp.deleteJsonArray(String)  //delete请求 参数以{application/json; charset=utf-8}形式提交,发送Json数组

 

 

以上14个请求方法你会发现,其实就6个类型,分别对应是Get、Head、Post、Put、Patch、Delete方法,只是其中Post、Put、Patch、Delete各有3个方法有不同形式的提交方式,只需要根据自己的需求选择就好。

 

如以上方法还不能满足你的需求,我们还可以通过@Param注解自定义请求方法,有关注解的使用,本文后续会详细介绍。

 

注:当调用xxxForm方法发送请求时,通过setMultiForm()方法或者调用addFile(String, File)添加文件时,内部会自动将参数以{multipart/form-data}方式提交

 

添加参数/请求头确定请求方法后,我们就可以调用一系列addXxx()方法添加参数/请求头,如下:

 


 
RxHttp.get("/service/...")       //发送get请求
    .add("key", "value")         //添加参数
    .addAll(new HashMap<>())     //通过Map添加多个参数
    .addHeader("deviceType", "android")     //添加请求头
    ...

 

任意请求,都可调用以上3个方法添加参数/请求头,当然,在不同的请求方式下,也会有不同的addXxx方法供开发者调用。

 

如下:

 


 
//postJson请求方法下会有更多addAll等方法可供调用
RxHttp.postJson("/service/...") //发送post Json请求
    .addAll(new JsonObject())   //通过json对象添加多个参数
    .addAll("{\"height\":180,\"weight\":70}") //通过json字符串添加多个参数
    ...

//postForm请求方法下会有一系列addFile方法可供调用
RxHttp.postForm("/service/...")  //发送post表单请求
    .addFile("file", new File("xxx/1.png")) //添加单个文件
    .addFile("fileList", new ArrayList<>()) //添加多个文件
    ...

 

以上只列出了几个常用的addXxx方法,更多方法请下载源码体验。

 

3.3.2、第二部曲:确定返回数据类型

 

添加好参数/请求头后,正式进入第二部曲,确定返回数据类型,我们通过asXxx方法确定返回类型,比如,我们要返回一个Student对象,就可以通过asObject(Class<T>)方法,如下:

 


 
RxHttp.postForm("/service/...")  //发送post表单请求
    .add("key", "value")         //添加参数,可调用多次
    .asObject(Student.class)    //返回Student类型
    .subscribe(student -> {   
        //请求成功,这里就能拿到 Student对象               
    }, throwable -> {         
        //请求失败                
    });    

 

 

如果要返回Student对象列表,则可以通过asList(Class<T>)方法,如下:

 


 
RxHttp.postForm("/service/...")  //发送post表单请求
    .add("key", "value")         //添加参数,可调用多次
    .asList(Student.class)       //返回List<Student>类型
    .subscribe(students -> {   
        //请求成功,这里就能拿到 Student对象列表               
    }, throwable -> {         
        //请求失败                
    });    

 

解析Response<T>类型数据然而,现实开发中,大多数人的接口,返回的数据结构都类似下面的这个样子

 


 
public class Response<T> {
    private int    code;
    private String msg;
    private T      data;
    //这里省略get、set方法
}

 

 

对于这种数据结构,按传统的写法,每次都要对code做判断,如果有100个请求,就要判断100次,真的会逼死强迫症患者。

 

RxHttp对于这种情况,给出完美的答案,比如Response<T>里面的T代表一个Student对象,则可以通过asResponse(Class<T>)方法获取,如下:

 


 
RxHttp.postForm("/service/...")   //发送post表单请求
    .add("key", "value")          //添加参数,可调用多次
    .asResponse(Student.class)    //返回Student类型
    .subscribe(student -> {   
        //请求成功,这里能拿到 Student对象               
    }, throwable -> {         
        //请求失败                
    });    

 

如果Response<T>里面的T代表一个List<Student>列表对象,则可以通过asResponseList(Class<T>)方法获取,如下

 


 
RxHttp.postForm("/service/...")   //发送post表单请求
    .add("key", "value")          //添加参数,可调用多次
    .asResponseList(Student.class)    //返回List<Student>类型
    .subscribe(students -> {   
        //请求成功,这里能拿到List<Student>列表对象               
    }, throwable -> {         
        //请求失败                
    });    

 

 

更多时候,我们的列表数据是分页的,类似下面的数据结构

 


 
{
    "code": 0,
    "msg": "",
    "data": {
        "totalPage": 0,
        "list": []
    }
}

 

此时,调用RxHttp的asResponsePageList(Class<T>)方法依然可以完美解决,如下:

 


 
RxHttp.postForm("/service/...")   //发送post表单请求
    .add("key", "value")          //添加参数,可调用多次
    .asResponsePageList(Student.class)    //返回PageList<Student>类型
    .subscribe(pageList -> {   
        //请求成功,这里能拿到PageList<Student>列表对象 
       int totalPage = pageList.getTotalPage();   //总页数
       List<Student> students = pageList.getData();  //单页列表数据        
    }, throwable -> {         
        //请求失败                
    });    

 

 

到这,估计很多人会问我:

 

  • 你的code在哪里判断的?

  • 我的code是100或者其它值才代表正确,怎么改?

  • 我的Response<T>类里面的字段名,跟你的都不一样,怎么该?

  • 你这成功的时候直接返回Response<T>里面的T,那我还要拿到code做其他的判断,执行不同业务逻辑,怎么办?

 

这里可以先告诉大家,asResponse(Class<T>)、asResponseList(Class<T>)、asResponsePageList(Class<T>)这3个方法并不是RxHttp内部提供的,而是通过自定义解析器生成,里面的code判断、Response<T>类都是开发者自定义的,如何自定义解析器,请查看本文5.1章节----自定义Parser。

 

接着回答第4个问题,如何拿到code做其他的业务逻辑判断,很简单,我们只需用OnError接口处理错误回调即可,如下:

 


 
RxHttp.postForm("/service/...")   //发送post表单请求
    .add("key", "value")          //添加参数,可调用多次
    .asResponse(Student.class)    //返回Student类型
    .subscribe(student -> {   
        //请求成功,这里能拿到 Student对象               
    }, (OnError) error -> {     //注意,这里要用OnError接口,其中error是一个ErrorInfo对象  
        //失败回调
        //拿到code字段,此时就可以对code做判断,执行不同的业务逻辑 
        int code = error.getErrorCode();     
        String errorMsg = error.getErrorMsg()  //拿到msg字段             
    });    

 

 

注:上面的OnError接口并非是RxHttp内部提供的,而是自定义的,在Demo里可以找到

以上介绍的5个asXxx方法,可以说基本涵盖80%以上的业务场景,接下来我们看看RxHttp都提供了哪些asXxx方法,如下:

 

 

RxHttp内部共提供了23个asXXX方法,其中:

 

  • 有7个是返回基本类型的包装类型,如:asInteger、asBoolean、asLong等等;

  • 还有7个是返回对象类型,如:asString、asBitmap、asList、asMap(3个)以及最常用asObject方法;

  • 剩下9个是asParser(Parser<T>)、 asUpload系列方法及asDownload系列方法。

 

duang、duang、duang !!! 划重点,这里我可以告诉大家,其实前面的14个方法,最终都是通过asParser(Parser<T>)方法实现的,具体实现过程,这里先跳过,后续会详细讲解。

 

3.3.3、第三部曲:订阅回调

 

这一步就很简单了,在第二部曲中,asXxx方法会返回Observable<T>对象,没错,就是RxJava内部的Observable<T>对象,此时我们便可通过subscribe系列方法订阅回调,如下:


 
//不处理任何回调
RxHttp.postForm("/service/...")   //发送post表单请求
    .add("key", "value")          //添加参数,可调用多次
    .asResponseList(Student.class)    //返回List<Student>类型
    .subscribe();    //不订阅任何回调

//仅订阅成功回调
RxHttp.postForm("/service/...")   //发送post表单请求
    .add("key", "value")          //添加参数,可调用多次
    .asResponseList(Student.class)    //返回List<Student>类型
    .subscribe(students -> {   
        //请求成功,这里能拿到List<Student>列表对象               
    });    

//订阅成功与失败回调
RxHttp.postForm("/service/...")   //发送post表单请求
    .add("key", "value")          //添加参数,可调用多次
    .asResponseList(Student.class)    //返回List<Student>类型
    .subscribe(students -> {   
        //请求成功,这里能拿到List<Student>列表对象               
    }, throwable -> {         
        //请求失败                
    });

//等等,省略

 

 

另外,我们还可以订阅请求开始/结束的回调,如下:


 
RxHttp.get("/service/...")
    .asString()
    .observeOn(AndroidSchedulers.mainThread())
    .doOnSubscribe(disposable -> {
        //请求开始,当前在主线程回调
    })
    .doFinally(() -> {
        //请求结束,当前在主线程回调
    })
    .as(RxLife.as(this))  //感知生命周期
    .subscribe(pageList -> {
        //成功回调,当前在主线程回调
    }, (OnError) error -> {
        //失败回调,当前在主线程回调
    });

 

到这,请求三部曲介绍完毕,接着,将介绍其它常用的功能

 

3.4、初始化

 


 
//设置debug模式,默认为false,设置为true后,发请求,过滤"RxHttp"能看到请求日志
RxHttp.setDebug(boolean debug)
//非必须,只能初始化一次,第二次将抛出异常
RxHttp.init(OkHttpClient okHttpClient)
//或者,调试模式下会有日志输出
RxHttp.init(OkHttpClient okHttpClient, boolean debug)

 

此步骤是非必须的,如需要添加拦截器等其他业务需求,则可调用init方法进行初始化,不初始化或者传入null即代表使用默认OkHttpClient对象,建议在Application中初始化,默认的OkHttpClient对象在HttpSender类中可以找到,如下:

 


 
private static OkHttpClient getDefaultOkHttpClient() {                              
    X509TrustManager trustAllCert = new X509TrustManagerImpl();                     
    SSLSocketFactory sslSocketFactory = new SSLSocketFactoryImpl(trustAllCert);     
    return new OkHttpClient.Builder()                                               
        .connectTimeout(10, TimeUnit.SECONDS)                                       
        .readTimeout(10, TimeUnit.SECONDS)                                          
        .writeTimeout(10, TimeUnit.SECONDS)                                         
        .sslSocketFactory(sslSocketFactory, trustAllCert) //添加信任证书                  
        .hostnameVerifier((hostname, session) -> true) //忽略host验证                   
        .build();                                                                   
}                                                                                   

 

虽然初始化是非必须的,但是建议大家传入自定义的OkHttpClient对象,一来,自定义的OkHttpClient能最大化满足自身的业务;二来,随着RxHttp版本的升级,默认的OkHttpClient可能会发生变化(虽然可能性很小),故建议自定义OkHttpClient对象传入RxHttp。

 

3.5、公共参数/请求头

 

RxHttp支持为所有的请求添加公共参数/请求头,当然,如果你希望某个请求不添加公共参数/请求头,也是支持的,而且非常简单。如下:

 


 
RxHttp.setOnParamAssembly(new Function() {
    @Override
    public Param apply(Param p) { //此方法在子线程中执行,即请求发起线程
        Method method = p.getMethod();
        if (method.isGet()) {     //可根据请求类型添加不同的参数
        } else if (method.isPost()) {
        }
        return p.add("versionName", "1.0.0")//添加公共参数
                .addHeader("deviceType", "android"); //添加公共请求头
    }
});

 

我们需要调用RxHttp.setOnParamAssembly(Function)方法,并传入一个Function接口对象,每次发起请求,都会回调该接口。

 

当然,如果希望某个请求不回调该接口,即不添加公共参数/请求头,则可以调用setAssemblyEnabled(boolean)方法,并传入false即可,如下:


 
RxHttp.get("/service/...")       //get请求 
    .setAssemblyEnabled(false)   //设置是否添加公共参数/头部,默认为true    
    .asString()                  //返回字符串数据    
    .subscribe(s -> {            //这里的s为String类型
        //请求成功                                         
    }, throwable -> {                                  
        //请求失败                                         
    });                                                

 

3.6、多域名/动态域名

 

3.6.1、多域名

 

现实开发中,我们经常会遇到多个域名的情况,其中1个为默认域名,其它为非默认域名,对于这种情况,RxHttp提供了@DefaultDomain()、@Domain()这两个注解来标明默认域名和非默认域名,如下:

 


 
public class Url {
    @DefaultDomain() //设置为默认域名
    public static String baseUrl = "https://www.wanandroid.com/"

    @Domain(name = "BaseUrlBaidu") //非默认域名,并取别名为BaseUrlBaidu
    public static String baidu = "https://www.baidu.com/";

    @Domain(name = "BaseUrlGoogle") //非默认域名,并取别名为BaseUrlGoogle
    public static String google = "https://www.google.com/";
}

 

 

通过@Domain()注解标注非默认域名,就会在RxHttp类中生成setDomainToXxxIfAbsent()方法,其中Xxx就是注解中取的别名。

 

上面我们使用了两个@Domain()注解,此时(需要Rebuild一下项目)就会在RxHttp类中生成setDomainToBaseUrlBaiduIfAbsent()、setDomainToBaseUrlGoogleIfAbsent()这两方法,此时发请求,我们就可以使用指定的域名,如下:

 

//使用默认域名,则无需添加任何额外代码
//此时 url = "https://www.wanandroid.com/service/..." 
RxHttp.get("/service/...")
    .asString()  
    .subscribe();

//手动输入域名,此时 url = "https://www.mi.com/service/..."
RxHttp.get("https://www.mi.com/service/...")
    .asString()  
    .subscribe();

//手动输入域名时,若再次指定域名,则无效
//此时 url = "https://www.mi.com/service/..."
RxHttp.get("https://www.mi.com/service/...")
    .setDomainToBaseUrlBaiduIfAbsent()  //此时指定Baidu域名无效
    .asString()  
    .subscribe();

//使用谷歌域名,此时 url = "https://www.google.com/service/..."       
RxHttp.get("/service/...")
    .setDomainToBaseUrlGoogleIfAbsent() //指定使用Google域名
    .asString()  
    .subscribe();

 

通过以上案例,可以知道,RxHttp共有3种指定域名的方式,按优先级排名分别是:手动输入域名 > 指定非默认域名 > 使用默认域名。

 

3.6.2、动态域名

 

现实开发中,也会有动态域名切换的需求,如域名被封、或者需要根据服务端下发的域名去配置,这对于RxHttp来说简直就是 so easy !!! 我们只需要对BaseUrl重新赋值,此时发请求便会立即生效,如下:

 

//此时 url = "https://www.wanandroid.com/service/..."
RxHttp.get("/service/...")
    .asString()  
    .subscribe();

Url.baseUrl = "https://www.qq.com"; //动态更改默认域名,改完立即生效,非默认域名同理
//此时 url = "https://www.qq.com/service/..."
RxHttp.get("/service/...")
    .asString()  
    .subscribe();

 

3.7、关闭请求

 

我们知道,在Activity/Fragment中发起请求,如果页面销毁时,请求还未结束,就会有内存泄漏的危险,因此,我们需要在页面销毁时,关闭一些还未完成的请求,RxHttp提供了两种关闭请求的方式,分别是自动+手动。

 

3.7.1、自动关闭请求

 

自动关闭请求,需要引入本人开源的另一个库RxLife,先来看看如何用:

https://github.com/liujingxing/RxLife


 
//以下代码均在FragmentActivty/Fragment中调用

RxHttp.postForm("/service/...")
    .asString()
    .as(RxLife.as(this)) //页面销毁、自动关闭请求
    .subscribe();
    //或者
RxHttp.postForm("/service/...")
    .asString()
    .as(RxLife.asOnMain(this)) //页面销毁、自动关闭请求 并且在主线程回调观察者
    .subscribe();

//kotlin用户,请使用life或lifeOnMain方法,如下:
RxHttp.postForm("/service/...")
    .asString()
    .life(this) //页面销毁、自动关闭请求
    .subscribe();
    //或者
RxHttp.postForm("/service/...")
    .asString()
    .lifeOnMain(this) //页面销毁、自动关闭请求 并且在主线程回调观察者
    .subscribe();

 

上面的this为LifecycleOwner接口对象,我们的FragmentActivity/Fragment均实现了这个接口,所有我们在FragmentActivity/Fragment中可以直接传this。

 

3.7.2、手动关闭请求

 

手动关闭请求,我们只需要在订阅回调的时候拿到Disposable对象,通过该对象可以判断请求是否结束,如果没有,就可以关闭请求,如下:

 


 
//订阅回调,可以拿到Disposable对象
Disposable disposable = RxHttp.get("/service/...")
    .asString()  
    .subscribe(s -> { 
       //成功回调
    }, throwable -> {
       //失败回调
    });

if (!disposable.isDisposed()) {  //判断请求有没有结束
    disposable.dispose();       //没有结束,则关闭请求
}                              

 

 

3.8、文件上传/下载/进度监听

 

RxHttp可以非常优雅的实现上传/下载及进度的监听,是骡子是马,拉出来溜溜

 

3.8.1上传

 

通过addFile系列方法添加文件,如下:

 

RxHttp.postForm("/service/...") //发送Form表单形式的Post请求  
    .addFile("file1", new File("xxx/1.png"))  //添加单个文件      
    .addFile("fileList", new ArrayList<>())   //通过List对象,添加多个文件     
    .asString()                                      
    .subscribe(s -> {                              
        //上传成功                                     
    }, throwable -> {                              
        //上传失败                                     
    });                                            

 

通过asUpload系列方法监听上传进度,如下:

 

RxHttp.postForm("/service/...") //发送Form表单形式的Post请求                                    
    .addFile("file1", new File("xxx/1.png"))                                         
    .addFile("file2", new File("xxx/2.png"))                                         
    .asUpload(progress -> {                                                          
        //上传进度回调,0-100,仅在进度有更新时才会回调                                                  
        int currentProgress = progress.getProgress(); //当前进度 0-100                   
        long currentSize = progress.getCurrentSize(); //当前已上传的字节大小                   
        long totalSize = progress.getTotalSize();     //要上传的总字节大小                    
    }, AndroidSchedulers.mainThread())   //指定回调(进度/成功/失败)线程,不指定,默认在请求所在线程回调                                           
    .subscribe(s -> {                                                                
        //上传成功                                                                       
    }, throwable -> {                                                                
        //上传失败                                                                       
    });                                                                              

 

 

可以看到,跟上传的代码相比,我们仅仅是使用了asUpload(Consumer, Scheduler)方法替换asString()方法,第一个参数是进度监听接口,每当进度有更新时,都会回调该接口,第二个参数是指定回调的线程,这里我们指定了在UI线程中回调。

 

3.8.2、下载

 

下载使用asDownload(String)方法,传入本地路径即可

 

  //文件存储路径
String destPath = getExternalCacheDir() + "/" + System.currentTimeMillis() + ".apk";
RxHttp.get("http://update.9158.com/miaolive/Miaolive.apk")
    .asDownload(destPath) //注意这里使用asDownload操作符,并传入本地路径
    .subscribe(s -> {
        //下载成功,回调文件下载路径
    }, throwable -> {
        //下载失败
    });

 

 

3.8.3、带进度下载

 

带进度下载使用asDownload(String,Consumer,Scheduler)方法

 

  //文件存储路径
String destPath = getExternalCacheDir() + "/" + System.currentTimeMillis() + ".apk";
RxHttp.get("http://update.9158.com/miaolive/Miaolive.apk")
    .asDownload(destPath, progress -> {
        //下载进度回调,0-100,仅在进度有更新时才会回调,最多回调101次,最后一次回调文件存储路径
        int currentProgress = progress.getProgress(); //当前进度 0-100
        long currentSize = progress.getCurrentSize(); //当前已下载的字节大小
        long totalSize = progress.getTotalSize();     //要下载的总字节大小
    }, AndroidSchedulers.mainThread()) //指定主线程回调
    .subscribe(s -> {//s为String类型,这里为文件存储路径
        //下载完成,处理相关逻辑
    }, throwable -> {
        //下载失败,处理相关逻辑
    });

 

 

3.8.4、断点下载

 

断点下载相较于下载,仅需要调用setRangeHeader(long startIndex, long endIndex)方法传入开始及结束位置即可(结束位置不传默认为文件末尾),其它没有任何差别

 


 
String destPath = getExternalCacheDir() + "/" + "Miaobo.apk";
long length = new File(destPath).length(); //已下载的文件长度
RxHttp.get("http://update.9158.com/miaolive/Miaolive.apk")
    .setRangeHeader(length)  //设置开始下载位置,结束位置默认为文件末尾
    .asDownload(destPath)
    .subscribe(s -> { //s为String类型
        //下载成功,处理相关逻辑
    }, throwable -> {
        //下载失败,处理相关逻辑
    });

 

 

3.8.5、带进度断点下载

 

带进度断点下载相较于带进度下载仅需要调用setRangeHeader方法传入开始及结束位置即可(结束位置不传默认为文件末尾),其它没有任何差别

 


 
String destPath = getExternalCacheDir() + "/" + "Miaobo.apk";
long length = new File(destPath).length(); //已下载的文件长度
RxHttp.get("http://update.9158.com/miaolive/Miaolive.apk")
    .setRangeHeader(length)  //设置开始下载位置,结束位置默认为文件末尾
    .asDownload(destPath, progress -> {
        //下载进度回调,0-100,仅在进度有更新时才会回调
        int currentProgress = progress.getProgress(); //当前进度 0-100
        long currentSize = progress.getCurrentSize(); //当前已下载的字节大小
        long totalSize = progress.getTotalSize();     //要下载的总字节大小
    }, AndroidSchedulers.mainThread()) //指定主线程回调
    .subscribe(s -> { //s为String类型
        //下载成功,处理相关逻辑
    }, throwable -> {
        //下载失败,处理相关逻辑
    });

 

 

注:上面带进度断点下载中,返回的进度会从0开始,如果需要衔接上次下载的进度,则调用asDownload(String,long,Consumer,Scheduler)方法传入上次已经下载好的长度(第二个参数),如下:

 


 
String destPath = getExternalCacheDir() + "/" + "Miaobo.apk";
long length = new File(destPath).length(); //已下载的文件长度
RxHttp.get("http://update.9158.com/miaolive/Miaolive.apk")
    .setRangeHeader(length)  //设置开始下载位置,结束位置默认为文件末尾
    .asDownload(destPath, length, progress -> {
        //下载进度回调,0-100,仅在进度有更新时才会回调
        int currentProgress = progress.getProgress(); //当前进度 0-100
        long currentSize = progress.getCurrentSize(); //当前已下载的字节大小
        long totalSize = progress.getTotalSize();     //要下载的总字节大小
    }, AndroidSchedulers.mainThread()) //指定主线程回调
    .subscribe(s -> { //s为String类型
        //下载成功,处理相关逻辑
    }, throwable -> {
        //下载失败,处理相关逻辑
    });

 

为了节省一下篇幅,让出源码解析的内容,这里省略了一些配置内容,也省略了一些扩展但是,但不影响整体阅读:

 


 

3.9、超时设置

3.10、设置Converter


 

3.11、请求加解密


 

3.12、指定请求/回调线程


 

3.13、 Retrofit用户

 

4

  原理剖析

 

 

4.1、工作流程

 

在RxHttp有4个重要的角色,分别是:

 

  • Param:RxHttp类中所有添加的参数/请求头/文件都交由它处理,它最终目的就是为了构建一个Request对象

  • HttpSender :它负责从Param对象中拿到Request对象,从而执行请求,最终返回Response对象

  • Parser:它负责将HttpSender返回的Response对象,解析成我们期望的实体类对象,也就是泛型T

  • RxHttp:它像一个管家,指挥前面3个角色做事情,当然,它也有自己的事情要做,比如:请求线程的调度,BaseUrl的处理、允许开发者自定义API等等

 

为此,我画了一个流程图,可以直观的了解到RxHttp的大致工作流程

 

 

我想应该很好理解,RxHttp要做的事情,就是把添加的参数/请求头等全部丢给Param处理,自己啥事也不敢;

 

随后将Param交给HttpSender,让它去执行请求,执行完毕,返回Response对象;

 

接着又将Response对象丢给Parser去做数据解析工作,并返回实体类对象T;

 

最后,将T通过回调传给开发者,到此,一个请求就处理完成。

 

4.2、Param

 

首先,附上一张Param类的继承关系图

 

 

下面将从上往下对上图中的类做个简单的介绍:

 

  • IHeaders:接口类,里面定义了一系列addHeader方法

  • IParam:接口类,里面定义了add(String,Object)、addAll(Map)等方法,

  • IRequest:接口类,里面定义了一系列getXxx方法,通过这些方法最终构建一个Request对象

  • Param:接口类,是一个空接口,继承了前面3个接口,里面有一系列静态方法可以获取到Param的具体实现类

  • AbstractParam:Param接口的抽象实现类,实现了Param接口的所有方法

  • IFile:接口类,里面定义了一系列addFile方法

  • IUploadLengthLimit:接口类,里面就定义了一个checkLength()方法,用于限制文件上传大小

  • NoBodyParam:Param的具体实现类,Get、Head请求就是通过该类去实现的

  • JsonParam:Param的具体实现类,调用RxHttp.xxxJson(String)请求方法时,内部就是通过该类去实现的

  • JsonArrayParam:Param的具体实现类,调用RxHttp.xxxJsonArray(String)请求方法时,内部就是通过该类去实现的

  • FormParam:Param的具体实现类,同时又实现了IFile、IUploadLengthLimit两个接口,调用RxHttp.xxxForm(String)请求方法时,内部就是通过该类去实现的

 

4.3、HttpSender

 

HttpSender可以把它理解为请求发送者,里面声明OkHttpClient对象和一系列静态方法,我们来简单看下:


 
public final class HttpSender {

    private static OkHttpClient mOkHttpClient; //只能初始化一次,第二次将抛出异常
    //处理化OkHttpClient对象
    public static void init(OkHttpClient okHttpClient) {
        if (mOkHttpClient != null)
            throw new IllegalArgumentException("OkHttpClient can only be initialized once");
        mOkHttpClient = okHttpClient;
    }

    //通过Param对象同步执行一个请求
    public static Response execute(@NonNull Param param) throws IOException {
        return newCall(param).execute();
    }

    static Call newCall(Param param) throws IOException {
        return newCall(getOkHttpClient(), param);
    }
    //所有的请求,最终都会调此方法拿到Call对象,然后执行请求
    static Call newCall(OkHttpClient client, Param param) throws IOException {
        param = RxHttpPlugins.onParamAssembly(param);
        if (param instanceof IUploadLengthLimit) {
            ((IUploadLengthLimit) param).checkLength();
        }
        Request request = param.buildRequest();  //通过Param拿到Request对象
        LogUtil.log(request);
        return client.newCall(request);
    }

    //省略了部分方法
}

 

这里我们重点看下newCall(OkHttpClient, Param)方法,该方法第一行就是为Param添加公共参数;然后判断Param有没有实现IUploadLengthLimit接口,有的话,检查文件上传大小,超出大小,则抛出IO异常;接着就是通过Param拿到Request对象;最后拿到Call对象,就可以发送一个请求。

 

4.4、Parser

 

先看下Parser继承结构图

 

 

这里对上图中的类做个简单的介绍

 

  • Parser:接口类,里面定义了一个T onParse(Response)方法,输入Response对象,输出实体类对象T

  • AbstractParser:抽象类,里面没有任何具体实现,主要作用是在构造方法内获取泛型类型

  • SimpleParser:是一个万能的解析器,可以解析任意数据结构,RxHttp内置的大部分asXxx方法,内部就是通过该解析器实现的

  • ListParser:是一个列表解析器,可以解析任意列表数据,内置asList(Class<T>)方法,就是通过该解析器实现的

  • MapParser:是一个Map解析器,可以解析任意Map数据类型,内置的asMap系列方法,就是通过该解析器实现的

  • BitmapParser:是一个Bitmap解析器,通过该解析器可以获得一个Bitmap对象,asBitmap()方法内部就是通过该解析器实现的

  • DownloadParser:文件下载解析器,用于文件下载,内置的一系列asDownload方法就是通过该解析器实现的

 

5

  小技巧

 

在这教大家一个小技巧,由于使用RxHttp发送请求都遵循请求三部曲,故我们可以在android studio 设置代码模版,如下

 

 

如图设置好后,写代码时,输入rp,就会自动生成模版,如下:

 

 

6

  小结

 

到这,RxHttp常用功能介绍完毕,你会发现,一切都是那么的美好,无论你是get、post、加密请求、自定义解析器,还是文件上传/下载/进度监听等等,皆遵循请求三部曲。

Android RxHttp在实战中的运用 【代码】Android RxHttp在实战中的运用。 阅读详情

相关推荐

新一代Android Studio插件:快速上手RxHttp,实现手机与Http请求的无缝连接

在订阅的回调中,你可以处理服务器返回的响应数据,或者处理请求发生的异常情况。在订阅的回调中,你可以处理服务器返回的响应数据,或者处理请求发生的异常情况。在上述示例中,我们通过add()方法添加了两个参数:“param1"和"value1"以及"param2"和"value2”。在上述示例中,我们通过add()方法添加了两个参数:“param1"和"value1"以及"param2"和"value2”。在上述示例中,我们使用post()方法发送一个POST请求,并通过add()方法添加了两个参数。

2301_79366332的博客 721

30秒上手新一代Http请求神器RxHttp

OkHttp3.14.x以上版本,最低要求为API21,如你想要兼容21以下,请依赖OkHttp3.12.x,该版本最低要求API9asXxx方法内部是通过RxJava实现的,而RxHttp2.2.0版本起,内部已剔除RxJava,如需使用,请自行依赖RxJava并告知RxHttp依赖的Rxjava版本将jitpack添加到项目的文件中,如下://使用kapt依赖rxhttp-compiler时必须android{//必须,java8或更高。

2501_90358684的博客 1020

细胞膜电学特性的分数阶微积分建模

分数阶微积分在细胞膜电学特性建模中的应用主要体现在对细胞膜的电容行为和神经元放电活动的更精确描述上。

冰河世纪20的博客 623

bat 发送post请求_RxHttp 让你眼前一亮的Http请求框架

本文作者作者:不怕天黑链接:https://juejin.im/post/5ded221a518825125d14a1d4本文由作者授权发布。1前言RxHttp在今年4月份一经推出,就受到了广大Android 开发者的喜爱,截止本文发表在github上已有800+star,为此,我自己也建个RxHttp&RxLife 的群(群号:378530627)https://github....

weixin_39678531的博客 1325

STM32F407与AD7766实战:如何用SPI+DMA实现高速ADC数据采集(附完整代码)

本文详细介绍了如何利用STM32F407的SPI接口与DMA控制器,高效稳定地驱动24位高精度ADC芯片AD7766,实现高速连续数据采集。通过对比传统中断方式的瓶颈,阐述了SPI+DMA方案如何大幅降低CPU负载,并提供了从硬件设计、CubeMX配置到核心驱动代码的完整实战指南,帮助工程师解决高速ADC数据采集中的性能难题。

weixin_29281941的博客 190

mcgs数据查表功能,用于大量数据对比查找对应数据,减少PLC代码

mcgs脚本实现数据查表功能

qq_24866535的博客 3271

RxHttp 一款让你眼前一亮的 Http 请求框架

本文系 RxHttp作者不怕天黑 向本博客投稿,并授权在本站发表。 1、前言 RxHttp在今年4月份一经推出,就受到了广大Android 开发者的喜爱,截止本文发表在github上已有1100+star,为此,我自己也建个RxHttp&RxLife 的群(群号:378530627)目前群里也有将近120号人,里面有不少小伙伴提了很多有价值的创意,才使得RxHttp一直坚持走到了现在,在此...

技术小黑屋 1906

IMU标定中的Allen方差

Allen方差 Allen方差是IMU标定任务中的常用工具。IMU标定可以分为确定性误差和随机误差,确定性误差包括:scale、bias、misalignment。随机误差则主要是高斯白噪声和bias随机游走。Allen方差主要用于标定随机误差。 Allen方差获取 Allen方差的计算方法如下: 保持IMU静止, 采集N个数据点。 将N个点定长分组,常用的交叠式Allen方差如下(n=3): 对于每个子集,计算均值后,计算相邻两组的方差,得到的时间-方差曲线即为Allen方差。 Alle

realjc的博客 5737

2024年RxHttp 让你眼前一亮的Http请求框架(3),发布面试结果文案

asDownload(destPath, AndroidSchedulers.mainThread(), progress -> { //第二个参数指定主线程回调。.as(RxLife.asOnMain(this)) //主线程回调,并在页面销毁自动关闭请求(如果还未关闭的话).observeOn(AndroidSchedulers.mainThread()) //指定在主线程回调。.setAssemblyEnabled(false) //设置是否添加公共参数/头部,默认为true。

2401_84853048的博客 545

【脑电信号处理与特征提取】P2-夏晓磊:脑电的神经起源与测量

ElectroEncephaloGraphyTherefore, EEG produces a graphed representation of the electrical activity occurring in a person’s brain.(把一个人的大脑中的电活动画出来)脑电头皮表面记录到的大脑活动产生的电信号(微伏)。(记录位置:硬脑膜/大脑皮层表面- ECoG,神经元群- LFP与MUR/MUA:活动位置:心电、眼电、肌电等)脑电图电压随时间变化的波形图。

m0_51474171的博客 1895

阿里云大模型 ACP 认证教材内容突变?这些改动藏着通关密码,不看亏大!

【摘要】核心章节大换血,安全合规融入实战场景,大模型微调用数学深度解析,部署章节带来阿里云产品对比实战攻略,甚至整章内容被替换成藏满学习彩蛋的行业趋势指南。这些改动不仅重塑考试重点,更暗藏官方命题风向——安全合规考场景方案,微调原理考几何解析,部署设计考分析框架。无论你是数学小白还是部署新手,这篇攻略都将带你吃透变动逻辑,附赠急救包和考点清单,帮你抓住这些“隐形加分项”,速来解锁通关秘籍!

davidkorhenn的博客 1755

2024年RxHttp 让你眼前一亮的Http请求框架(6),2024年最新字节跳动面试内容

/rxjava2 (RxJava2/Rxjava3二选一,使用asXxx方法时必须)implementation ‘com.github.liujingxing.rxlife:rxlife-rxjava2:2.2.1’ //管理RxJava2生命周期,页面销毁,关闭请求@DefaultDomain //设置为默认域名RxHttp.get(“http://…”) //第一步, 通过get、postXxx、putXxx等方法,确定请求类型。

2401_84853048的博客 912

【电脑技巧】CPU正常运行时间过长,怎么解决?

目录 问题描述 解决方案 1、问题描述 不少同志都遇到过这样的问题:按【Ctrl + alt + delete】打开任务管理器,切到“性能”选项卡下,发现自己电脑的CPU正常运行时间竟然为好几十天!很多人担心这会不会影响电脑的寿命?于是很想知道这是怎么回事,以及如何解决这个问题。 我在此解答一下,这是由于你的电脑开启了“快速启动”这一选项的缘故,只要把这一选项关闭,问题就解决了。 2、解决方案 怎样关闭“快速启动”呢?按照如下的步骤来即可。 顺便声明一下,笔者的电脑配置: 使用电脑:联想Yoga 14

橄榄树下的孩子 3万+

RxHttp 2000+star,协程请求,仅需三步

map操作符很好理解,RxJava及协程的Flow都有该操作符,功能都是一样,用于转换对象,如下:.toStr().map { it.length } //String转Int.tryAwait() //这里返回 Student?对象,即有可能为空RxHttp内置了一系列强大又好用的操作符,然而肯定满足不了所有的业务场景,此时我们就可以考虑自定义操作符自定义takeLast操作符如我们有这样一个需求,自定义需要在列表尾部取n条数据,不足n条,返回全部前面我们介绍了take。

2301_82257730的博客 895

YOLO十年演进:从CNN到Transformer再到MoE,我看懂了2026年目标检测的落地风向标

技术永远是为业务服务的,能解决真实问题的技术,才是有价值的。YOLO的十年演进,从CNN到Transformer再到MoE,从来都不是学术上的炫技,而是一步一步解决工业落地的痛点:从让实时检测成为可能,到解决复杂场景的漏检误检,再到打破精度和算力的死局,每一步都踩在了工业落地的真实需求上。很多新入行的朋友,总喜欢追新,今天换Transformer,明天堆MoE,觉得模型越新、参数越大,就越厉害。

专注于Python爬虫开发,分享爬虫技巧、项目实战与反爬经验,使用Scrapy、BeautifulSoup等工具,解决数据抓取难题。 749

SAP B1中文培訓教材_SDK

公司内部培训资料,对开发工具 ,DIAPI, UIAPI,Add-ON有详细解说

volley怎么获取http请求的返回值_RxHttp 2000+star,协程请求,仅需三步

原文链接:RxHttp 2000+star,协程请求,仅需三步1、前言Hello,各位小伙伴,3个月不见,我又回来了,这3个月里,一直致力于RxHttp项目的维护工作,截止本文发表,RxHttp已更新至v2.3.3版本,github上已突破2200+star,对于一个开源仅一年多一点的项目,可以说取得了不错的成绩,在这里,感谢大家的支持与肯定,RxHttp一定会越来越好,再次感谢大家。在这之前,R...

weixin_39520988的博客 338

数学建模模型总结

这是本人在两年内准备参加数学建模竞赛搜集到的模型资料,已经经过了本人的筛选和整理,希望能够对准备参加数学建模竞赛的学弟学妹们提供一些帮助!

RxHttp 全网Http缓存最优解

1、前言 距离上一文RxHttp 让你眼前一亮的Http请求框架的发表,已过去两周,文章一经发表,RxHttp就收获了众多的好评,Github上Star数,也正式突破了1000,这对于我来说,是非常有动力的事情,感谢大家的支持,我再接再厉。 也有很多人跟说我,希望RxHttp能支持协程和缓存这两大功能,这不,非常好用的缓存公共就能来了,看完本文,相信你会再一次爱上RxHttp。另外,协程也已经在路...

刘敬兴的博客 779

Data-Structures-and-Algorithm-Analysis-in-Java.pdf

作者: Weiss, Mark A. 出版社: Addison Wesley Data Structures and Algorithm Analysis in Java is an “advanced algorithms” book that fits between traditional CS2 and Algorithms Analysis courses. In the old ACM Curriculum Guidelines, this course was known as CS7. This text is for readers who want to learn good programming and algorithm analysis skills simultaneously so that they can develop such programs with the maximum amo...

VC中sqlite的使用

在VC中对sqlite的使用,实现数据库大批数据的快速插入,读取数据库中的数据在ListCtrl中显示

RxHttp-完美适配Android-10-11-上传-下载-进度监听

有任何问题,欢迎广大网友一起来交流,分享高阶Android学习视频资料和面试资料包~偷偷说一句:群里高手如云,欢迎大家加群和大佬们一起交流讨论啊!《Android学习笔记总结+移动架构视频+大厂面试真题+项目实战源码》点击传送门,即可获取!ze() //要上传的总字节大小//成功回调,这里返回sd卡存储路径}, {//异常失败})复制代码有任何问题,欢迎广大网友一起来交流,分享高阶Android学习视频资料和面试资料包~

2301_82242484的博客 752
上一篇: ViewPager2 正式版本发布,学不动也要学!
下一篇: android 混淆问题
ZyClient
博客等级 码龄10年 29粉丝 60原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值