RxHttp 在v2.0版本中加入对协程的支持,收到了广大kotlin用户的喜好,他们也不由感慨,原来协程发请求还能如此优雅,比retrofit强大的不止一点点,然而,这就够了吗?远远不够,为啥,由于还有痛点没解决,为此,我也收集几个目前网络请求遇到的痛点,以下:java
async
操做符处理异步问题,但用到时,每次还要包装一次,不能接受等等,其实还有不少小细节的问题,这里就就不一一列举了。git
正因有以上问题,因此RxHttp v2.2.0版本就来了,该版本主要改动以下github
asysn
、timeout
、retry
、tryAwait
等等gradle依赖json
dependencies {
//必须
implementation 'com.ljx.rxhttp:rxhttp:2.2.0'
kapt 'com.ljx.rxhttp:rxhttp-compiler:2.2.0' //生成RxHttp类
//如下均为非必须
//管理协程生命周期,页面销毁,关闭请求
implementation 'com.ljx.rxlife:rxlife-coroutine:2.0.0'
//Converter 根据本身需求选择 RxHttp默认内置了GsonConverter
implementation 'com.ljx.rxhttp:converter-jackson:2.2.0'
implementation 'com.ljx.rxhttp:converter-fastjson:2.2.0'
implementation 'com.ljx.rxhttp:converter-protobuf:2.2.0'
implementation 'com.ljx.rxhttp:converter-simplexml:2.2.0'
}
复制代码
注:纯Java项目,请使用annotationProcessor替代kapt;依赖完,记得rebuild,才会生成RxHttp类缓存
欢迎加入RxHttp&RxLife交流群:378530627网络
相信还有以前没了解过RxHttp的同窗,这里贴出RxHttp请求流程图,记住该图,你就掌握了RxHttp的精髓,以下: 框架
val str = RxHttp.get("/service/...") //第一步,肯定请求方式,能够选择postForm、postJson等方法
.toStr() //第二步,确认返回类型,这里表明返回String类型
.await() //第二步,使用await方法拿到返回值
复制代码
怎么样,是否是很是简单?异步
该操做符很是强大,不只作到了失败重试,还作到了周期性失败重试,即间隔几秒后重试,来看下完整的方法签名async
/** * 失败重试,该方法仅在使用协程时才有效 * @param times 重试次数, 默认Int.MAX_VALUE 表明不断重试 * @param period 重试周期, 默认为0, 单位: milliseconds * @param test 重试条件, 默认为空,即无条件重试 */
fun retry( times: Int = Int.MAX_VALUE, period: Long = 0, test: ((Throwable) -> Boolean)? = null
)
复制代码
retry()
方法共有3个参数,分别是重试次数、重试周期、重试条件,都有默认值,3个参数能够随意搭配,如:函数
retry() //无条件、不间断、一直重试
retry(2) //无条件、不间断、重试两次
retry(2, 1000) //无条件 间隔1s 重试2此
retry { it is ConnectException } //有条件、不间断、一直重试
retry(2) { it is ConnectException } //有条件、不间断、重试2次
retry(2, 1000) { it is ConnectException } //有条件、间隔1s、重试2次
retry(period = 1000) { it is ConnectException } //有条件、间断1s、一直重试
复制代码
前两个参数相信你们一看就能明白,这里对第3个参数额外说一下,经过第三个参数,咱们能够拿到Throwable
异常对象,咱们能够对异常作判断,若是须要重试,就返回true,不须要就返回false,下面看看具体代码
val student = RxHttp.postForm("/service/...")
.toClass<Student>()
.retry(2, 1000) { //重试2次,每次间隔1s
it is ConnectException //若是是网络异常就重试
}
.await()
复制代码
OkHttp提供了全局的读、写及链接超时,有时咱们也须要为某个请求设置不一样的超时时长,此时就能够用到RxHttp的timeout(Long)
方法,以下:
val student = RxHttp.postForm("/service/...")
.toClass<Student>()
.timeout(3000) //超时时长为3s
.await()
复制代码
若是咱们由两个请求须要并行时,就可使用该操做符,以下:
//同时获取两个学生信息
suspend void initData() {
val asyncStudent1 = RxHttp.postForm("/service/...")
.toClass<Student>()
.async() //这里会返回Deferred<Student>
val asyncStudent2 = RxHttp.postForm("/service/...")
.toClass<Student>()
.async() //这里会返回Deferred<Student>
//随后调用await方法获取对象
val student1 = asyncStudent1.await()
val student2 = asyncStudent2.await()
}
复制代码
delay
操做符是请求结束后,延迟一段时间返回;而startDelay
操做符则是延迟一段时间后再发送请求,以下:
val student = RxHttp.postForm("/service/...")
.toClass<Student>()
.delay(1000) //请求回来后,延迟1s返回
.await()
val student = RxHttp.postForm("/service/...")
.toClass<Student>()
.startDelay(1000) //延迟1s后再发送请求
.await()
复制代码
有些状况,咱们不但愿请求出现异常时,直接走异常回调,此时咱们就能够经过两个操做符,给出默认的值,以下:
//根据异常给出默认值
val student = RxHttp.postForm("/service/...")
.toClass<Student>()
.timeout(100) //超时时长为100毫秒
.onErrorReturn {
//若是时超时异常,就给出默认值,不然,抛出原异常
return@onErrorReturn if (it is TimeoutCancellationException)
Student()
else
throw it
}
.await()
//只要出现异常,就返回默认值
val student = RxHttp.postForm("/service/...")
.toClass<Student>()
.timeout(100) //超时时长为100毫秒
.onErrorReturnItem(Student())
.await()
复制代码
若是你不想在异常时返回默认值,又不想异常是影响程序的执行,tryAwait
就派上用场了,它会在异常出现时,返回null,以下:
val student = RxHttp.postForm("/service/...")
.toClass<Student>()
.timeout(100) //超时时长为100毫秒
.tryAwait() //这里返回 Student? 对象,即有可能为空
复制代码
map
操做符很好理解,RxJava即协程的Flow都有该操做符,功能都是同样,用于转换对象,以下:
val student = RxHttp.postForm("/service/...")
.toStr()
.map { it.length } //String转Int
.tryAwait() //这里返回 Student? 对象,即有可能为空
复制代码
以上操做符,可随意搭配使用,但调用顺序的不一样,产生的效果也不同,这里悄悄告诉你们,以上操做符只会对上游代码产生影响。
如timeout及retry
:
val student = RxHttp.postForm("/service/...")
.toClass<Student>()
.timeout(50)
.retry(2, 1000) { it is TimeoutCancellationException }
.await()
复制代码
以上代码,只要出现超时,就会重试,而且最多重试两次。
但若是timeout
、retry
互换下位置,就不同了,以下:
val student = RxHttp.postForm("/service/...")
.toClass<Student>()
.retry(2, 1000) { it is TimeoutCancellationException }
.timeout(50)
.await()
复制代码
此时,若是50毫秒内请求没有完成,就会触发超时异常,而且直接走异常回调,不会重试。为何会这样?缘由很简单,timeout及retry
操做符,仅对上游代码生效。如retry操做符,下游的异常是捕获不到的,这就是为何timeout在retry下,超时时,重试机制没有触发的缘由。
在看timeout
和startDelay
操做符
val student = RxHttp.postForm("/service/...")
.toClass<Student>()
.startDelay(2000)
.timeout(1000)
.await()
复制代码
以上代码,一定会触发超时异常,由于startDelay,延迟了2000毫秒,而超时时长只有1000毫秒,因此一定触发超时。 但互换下位置,又不同了,以下:
val student = RxHttp.postForm("/service/...")
.toClass<Student>()
.timeout(1000)
.startDelay(2000)
.await()
复制代码
以上代码正常状况下,都能正确拿到返回值,为何?缘由很简单,上面说过,操做符只会对上游产生影响,下游的startDelay
延迟,它是无论的,也管不到。
在以上示例中,咱们统一用到await/tryAwait
操做符获取请求返回值,它们都是suspend
挂起函数,须要在另外一个suspend
挂起函数或者协程中才能被调用,故咱们提供了RxLifeScope库来处理协程开启、关闭及异常处理,用法以下:
在FragemntActivity/Fragment/ViewModel环境下
在该环境下,直接调用rxLifeScope
对象的lanuch
方法开启协程便可,以下:
rxLifeScope.lanuch({
//协程代码块,运行在UI线程
val student = RxHttp.postForm("/service/...")
.toClass<Student>()
.await()
//可直接更新UI
}, {
//异常回调,这里能够拿到Throwable对象
})
复制代码
以上代码,会在页面销毁时,自动关闭协程,同时自动关闭请求,无需担忧内存泄露问题
非FragemntActivity/Fragment/ViewModel环境下
该环境下,咱们须要手动建立RxLifeScope
对象,随后调用lanuch
方法开启协程
val job = RxLifeScope().lanuch({
//协程代码块,运行在UI线程
val student = RxHttp.postForm("/service/...")
.toClass<Student>()
.await()
//可直接更新UI
}, {
//异常回调,这里能够拿到Throwable对象
})
//在合适的时机关闭协程
job.cancel()
复制代码
以上代码,因为未与生命周期绑定,故咱们须要在合适的时机,手动关闭协程,协程关闭,请求也会跟着关闭
监听协程开启/结束回调
以上咱们在lanuch
方法,传入协程运行回调及异常回调,咱们也能够传入协程开启及结束回调,以下:
rxLifeScope.launch({
//协程代码块
val student = RxHttp.postForm("/service/...")
.toClass<Student>()
.await()
//可直接更新UI
}, {
//异常回调,这里能够拿到Throwable对象,运行在UI线程
}, {
//开始回调,能够开启等待弹窗,运行在UI线程
}, {
//结束回调,能够销毁等待弹窗,运行在UI线程
})
复制代码
以上回调,均运行在UI线程
能够看到,前面文章开头提到超时/重试问题,就用timeout/retry
,延迟就用delay/startDelay
,出现异常不想中断协程的运行,就用onErrorReturn/onErrorReturnItem
或者tryAwait
,总之,一切都是那么的优雅。
RxHttp的优雅远不止这些,BaseUrl的处理,文件上传/下载/进度监听,缓存处理、业务code统一判断等等,处理的都使人叹为观止,
更多功能查看如下文章
协程用法:RxHttp ,比Retrofit 更优雅的协程体验
RxJava用法:RxHttp 让你眼前一亮的Http请求框架
最后,开源不易,写文章更不易,若是你以为不错RxHttp或给你带来了帮助,欢迎点赞收藏,以备不时之需,若是能够,再给个star,我将感激涕零,🙏🙏🙏🙏🙏🙏🙏🙏🙏🙏🙏🙏