RxHttp

Project Url: liujingxing/RxHttp
Introduction: OkHttp+RxJava 一条链发送请求,自动关闭未完成的请求,新一代 Http 请求神器
More: Author   ReportBugs   
Tags:

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

  • 支持 Get、Post、Put、Delete 等任意请求方式,可自定义请求方式
  • 支持 Json、DOM 等任意数据解析方法,可自定义数据解析器
  • 支持文件下载/上传,及进度的监听,并且支持断点下载
  • 支持在 Activity/Fragment 的任意生命周期方法,自动关闭未完成的请求
  • 支持添加公共参数/头部信息,且可动态更改 baseUrl
  • 支持请求串行和并行

注:RxHttp 是通过注解生成的,请使用@DefaultDomain 或@Domain 注解在 baseUrl 上,rebuild 一下项目,就能看到 RxHttp 类了。 注解处理器会在编译时检索注解,检索不到,就不会生成 RxHttp 类。

30 秒上手教程:https://juejin.im/post/5cfcbbcbe51d455a694f94df

详细介绍:https://juejin.im/post/5cbd267fe51d456e2b15f623

自动关闭请求用到的 RxLife 类,详情请查看RxLife 库

RxHttp&RxLife 交流群:378530627

Demo 演示

image

普通文本请求不便于展示,故这里只演示 Bitmap 加载及多任务断点下载,更多功能,请下载 Demo 体验

Gradle 引用方法

dependencies {
   implementation 'com.rxjava.rxhttp:rxhttp:1.1.4'
   annotationProcessor 'com.rxjava.rxhttp:rxhttp-compiler:1.1.4' //注解处理器,生成 RxHttp 类
   implementation 'com.rxjava.rxlife:rxlife:1.0.9'  //页面销毁,关闭请求,非必须

   // if you use kotlin
   kapt 'com.rxjava.rxhttp:rxhttp-compiler:1.1.4'
}

注:

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

compileOptions {
    sourceCompatibility JavaVersion.VERSION_1_8
    targetCompatibility JavaVersion.VERSION_1_8
}

Usage

首先,我们需要通过注解生成 RxHttp 类

public class Url {
    @DefaultDomain() //设置为默认域名
    public static String baseUrl = "http://ip.taobao.com/";
}

此时 rebuild 一下项目,就能看到 RxHttp 类了

请求三部曲

RxHttp.get("http://...")            //第一步,确定请求方式
    .asString()                     //第二步,使用 asXXX 系列方法确定返回类型
    .subscribe(s -> {               //第三部, 订阅观察者
        //成功回调
    }, throwable -> {
        //失败回调
    });

post

RxHttp.postForm("http://...")       //发送表单形式的 post 请求
    .asString()
    .subscribe(s -> {
        //成功回调
    }, throwable -> {
        //失败回调
    });

RxHttp.postJson("http://...")       //发送 Json 字符串形式的 post 请求
    //省略部分代码

添加参数

RxHttp.postForm("http://...")                //发送表单形式的 post 请求
    .add("key", "value")                     //添加参数
    .addHeader("headerKey", "headerValue")   //添加请求头
    .addFile("file", new File("xxx/1.png"))  //添加文件
    .asString()
    .subscribe(s -> {
        //成功回调
    }, throwable -> {
        //失败回调
    });

返回自定义的数据类型

RxHttp.postForm("http://...")     //发送表单形式的 post 请求
    .asObject(Student.class)      //返回 Student 对象
    .subscribe(student -> {
        //成功回调
    }, throwable -> {
        //失败回调
    });


RxHttp.postForm("http://...")     //发送表单形式的 post 请求
    .asList(Student.class)        //返回 List<Student>集合
    .subscribe(students -> {
        //成功回调
    }, throwable -> {
        //失败回调
    });

文件上传

RxHttp.postForm("http://...")                //发送 Form 表单形式的 Post 请求
    .addFile("file", new File("xxx/1.png"))  //添加文件
    .asString()
    .subscribe(s -> {
        //成功回调
    }, throwable -> {
        //失败回调
    });

文件下载

RxHttp.get("http://...")
    .asDownload("sd/xxx/1.apk") //传入本地路径
    .subscribe(s -> {
        //下载成功,回调文件下载路径
    }, throwable -> {
        //下载失败
    });

文件上传进度监听

RxHttp.postForm("http://...")
    .add("file1", new File("xxx/1.png"))
    .asUploadProgress()            //asUploadProgress 操作符,监听上传进度
    .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 返回结果并继续往下走
    .subscribe(s -> {             //这里 s 为 String 类型,可通过 asUploadProgress(Parser<T> parser)自定义返回类型
        //上传成功
    }, throwable -> {
        //上传失败
    });

文件下载进度监听

RxHttp.get("http://...")
    .asDownloadProgress("sd/xxx/1.apk") //传入本地路径
    .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)           //到这,说明下载完成,返回下载目标路径
    .subscribe(s -> {                   //s 为 String 类型,这里为文件存储路径
        //下载完成
    }, throwable -> {
        //下载失败
    });

断点下载、带进度回调

//断点下载,带进度
public void breakpointDownloadAndProgress() {
    String destPath = getExternalCacheDir() + "/" + "Miaobo.apk";
    File file = new File(destPath);
    long length = file.length();
    RxHttp.get("http://update.9158.com/miaolive/Miaolive.apk")
        .setRangeHeader(length)                //设置开始下载位置,结束位置默认为文件末尾
        .asDownloadProgress(destPath, length)  //如果需要衔接上次的下载进度,则需要传入上次已下载的字节数
        .observeOn(AndroidSchedulers.mainThread())
        .doOnNext(progress -> {
            //下载进度回调,0-100,仅在进度有更新时才会回调
            int currentProgress = progress.getProgress(); //当前进度 0-100
            long currentSize = progress.getCurrentSize(); //当前已下载的字节大小
            long totalSize = progress.getTotalSize();     //要下载的总字节大小
        })
        .filter(Progress::isCompleted)     //过滤事件,下载完成,才继续往下走
        .map(Progress::getResult)          //到这,说明下载完成,拿到 Http 返回结果并继续往下走
        .subscribe(s -> { //s 为 String 类型
            //下载成功,处理相关逻辑
        }, throwable -> {
            //下载失败,处理相关逻辑
        });
}

初始化

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

添加公共参数/头部及重新设置 url

//建议在 Application 里设置
RxHttp.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"); //添加公共请求头
    }
});

Activity/Fragment 销毁,自动关闭请求

RxHttp.postForm("http://...")    //发送表单形式的 post 请求
    .asString()
    .as(RxLife.as(this))         //页面销毁,自动关闭请求
    .subscribe(s -> {
        //成功回调
    }, throwable -> {
        //失败回调
    });

RxHttp.postForm("http://...")       //发送表单形式的 post 请求
    .asString()
    .as(RxLife.asOnMain(this))      //在主线程回调,并在页面销毁,自动关闭请求
    .subscribe(s -> {
        //成功回调
    }, throwable -> {
        //失败回调
    });

常用 api 介绍

RxHttp.postForm("/service/getIpInfo.php") //发送 Form 表单形式的 Post 请求
    .setDomainToUpdate9158IfAbsent()      //手动设置域名,不设置会添加默认域名,此方法是通过@Domain 注解生成的
    .tag("RxHttp.get")                    //为单个请求设置 tag
    .setUrl("http://...")                 //重新设置 url
    .setJsonParams("{"versionName":" 1.0 .0 "}")  //设置 Json 字符串参数,非 Json 形式的请求调用此方法没有任何效果
    .setAssemblyEnabled(false)                 //设置是否添加公共参数,默认为 true
    .cacheControl(CacheControl.FORCE_NETWORK)  //缓存控制
    .setParam(Param.postForm("http://..."))    //重新设置一个 Param 对象
    .add(new HashMap<>())                      //通过 Map 添加参数
    .add("key", "value")                       //添加 int 类型参数
    .addFile("file1", new File("xxx/1.png"))   //添加文件对象
    .addHeader("headerKey1", "headerValue1")   //添加头部信息
    .subscribeOn(Schedulers.io())  //指定请求线程,不指定默认在 IO 线程执行
    .asString()                   //使用 asXXX 系列方法确定返回类型,此时返回 Observable 对象
    .as(RxLife.asOnMain(this))    //主线程回调,并在页面销毁时,自动关闭未完成的请求
    .subscribe(s -> {    //订阅观察者
        //成功回调
    }, throwable -> {
        //失败回调
    });

混淆

RxHttp 作为开源库,可混淆,也可不混淆,如果不希望被混淆,请在 proguard-rules.pro 文件添加以下代码

-keep class rxhttp.**{*;}

小技巧

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

image

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

image

问题简答

最后,借此机会,简单解答一下读者反馈的问题

1、RxHttp 支持 Https 吗?

答:支持,RxHttp 内置默认的 OkHttpClient 对象,如下:

new OkHttpClient.Builder()
    .connectTimeout(10, TimeUnit.SECONDS)
    .readTimeout(10, TimeUnit.SECONDS)
    .writeTimeout(10, TimeUnit.SECONDS)
    .sslSocketFactory(sslSocketFactory, trustAllCert) //添加信任证书
    .hostnameVerifier((hostname, session) -> true) //忽略 host 验证
    .build();

2、RxHttp 支持缓存处理吗?

答:支持,但是 RxHttp 默认没有做任何缓存处理,如有需要,请自定义 OkHttpClient 对象开启缓存,并使用 RxHttp 发送请求时,使用cacheControl(CacheControl cacheControl)设置缓存策略

3、RxHttp 如何支持 session 或者 token?

答:session 或者 token 涉及到具体的业务逻辑,故 RxHttp 暂时并没有做深度封装。如有需要,可自定义 OkHttpClient 对象通过拦截器去实现。

4、RxHttp 支持 kotlin 吗?

答:必须支持,但是依赖注解处理器时,需要使用 kapt 代替 annotationProcessor

5、RxHttp 如何支持多任务列表下载

答:在最新的 Demo 中,已有案例,欢迎下载 Demo 体验

更新日志

1.1.4

  • RxHttp 类增加 setOnConverter,可用户对 Http 返回的结果进行解密

  • RxHttp 类增加 setConverterEnabled(boolean),可对单个设置接口不解密

  • 成功/失败回调日志里加入请求参数

1.1.1

  • 删除 fromXXX 等过时方法

  • 支持使用 RxHttp 类进行初始化,之前使用 HttpSender 类初始化的用户不受影响

1.1.0

  • 上传文件时,根据文件名称,自动确定 contentType,为空时,默认为 application/octet-stream

1.0.9

  • 增加 3 个 asMap 方法,通过该方法,可将服务器返回的数据解析成 Map 对象

  • 修复 HttpStatusCodeException 异常会打印两遍问题

  • 兼容 OkHttpClient 添加 HttpLoggingInterceptor 拦截器后,上传文件时,进度会达到 200%问题

1.0.8

  • 增加 Http 请求连接失败时的异常信息打印

  • 修复 1.0.7 版本中,一处由注解的生成的方法错误问题

1.0.7

  • RxHttp 类增加一系列'subscribeOnXXX'方法,通过该系列方法,指定请求在某个线程执行

  • 增加 BitmapParser 解析器,通过该解析器,可直接拿到 Bitmap 对象,详情查看 asBitmap 方法

  • RxHttp 类增加一系列'asXXX'方法,替代'fromXXX'/'downloadXXX'/'uploadXXX'方法,被替代的方法标记为过时,将在未来的版本删除

  • 增加 HttpStatusCodeException 异常类,可在 OnError 回调中捕获该异常

  • OkHttp 更新至 3.14.1,RxJava 更新至 2.2.8 版本,RxAndroid 更新至 2.1.1 版本

  • HttpSender 中一些方法标记为过时,这些方法将在未来的版本中删除,请尽快使用新方法替代

1.0.5

  • 增加一系列'addFile'方法,支持同一个 key 添加多个文件

  • PostFormParam 增加 setUploadMaxLength 方法,以限制文件上传最大长度

1.0.4

  • RxHttp 类增加 setRangeHeader、downloadProgress(String,Long)方法,以更好的支持断点下载

1.0.3

  • RxHttp 增加 setJsonParams(String) 方法,Json 形式的请求直接调用此方法传入 Json 字符串参数

1.0.2

  • 增加@DefaultDomain 注解,通过该注解,可以设置 baseUrl;
Support Me
Apps
About Me
Google+: Trinea trinea
GitHub: Trinea