前两个参数相信大家一看就能明白,这里对第3个参数额外说一下,通过第三个参数,我们可以拿到Throwable
异常对象,我们可以对异常做判断,如果需要重试,就返回true,不需要就返回false,下面看看具体代码
val student = RxHttp.postForm(“/service/…”)
.toClass()
.retry(2, 1000) { //重试2次,每次间隔1s
it is ConnectException //如果是网络异常就重试
}
.await()
OkHttp提供了全局的读、写及连接超时,有时我们也需要为某个请求设置不同的超时时长,此时就可以用到RxHttp的timeout(Long)
方法,如下:
val student = RxHttp.postForm(“/service/…”)
.toClass()
.timeout(3000) //超时时长为3s
.await()
如果我们由两个请求需要并行时,就可以使用该操作符,如下:
//同时获取两个学生信息
suspend void initData() {
val asyncStudent1 = RxHttp.postForm(“/service/…”)
.toClass()
.async() //这里会返回Deferred
val asyncStudent2 = RxHttp.postForm(“/service/…”)
.toClass()
.async() //这里会返回Deferred
//随后调用await方法获取对象
val student1 = asyncStudent1.await()
val student2 = asyncStudent2.await()
}
delay
操作符是请求结束后,延迟一段时间返回;而startDelay
操作符则是延迟一段时间后再发送请求,如下:
val student = RxHttp.postForm(“/service/…”)
.toClass()
.delay(1000) //请求回来后,延迟1s返回
.await()
val student = RxHttp.postForm(“/service/…”)
.toClass()
.startDelay(1000) //延迟1s后再发送请求
.await()
3.5、onErrorReturn、onErrorReturnItem异常默认值
有些情况,我们不希望请求出现异常时,直接走异常回调,此时我们就可以通过两个操作符,给出默认的值,如下:
//根据异常给出默认值
val student = RxHttp.postForm(“/service/…”)
.toClass()
.timeout(100) //超时时长为100毫秒
.onErrorReturn {
//如果时超时异常,就给出默认值,否则,抛出原异常
return@onErrorReturn if (it is TimeoutCancellationException)
Student()
else
throw it
}
.await()
//只要出现异常,就返回默认值
val student = RxHttp.postForm(“/service/…”)
.toClass()
.timeout(100) //超时时长为100毫秒
.onErrorReturnItem(Student())
.await()
如果你不想在异常时返回默认值,又不想异常是影响程序的执行,tryAwait
就派上用场了,它会在异常出现时,返回null,如下:
val student = RxHttp.postForm(“/service/…”)
.toClass()
.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()
.timeout(50)
.retry(2, 1000) { it is TimeoutCancellationException }
.await()
以上代码,只要出现超时,就会重试,并且最多重试两次。
但如果timeout
、retry
互换下位置,就不一样了,如下:
val student = RxHttp.postForm(“/service/…”)
.toClass()
.retry(2, 1000) { it is TimeoutCancellationException }
.timeout(50)
.await()
此时,如果50毫秒内请求没有完成,就会触发超时异常,并且直接走异常回调,不会重试。为什么会这样?原因很简单,timeout及retry
操作符,仅对上游代码生效。如retry操作符,下游的异常是捕获不到的,这就是为什么timeout在retry下,超时时,重试机制没有触发的原因。
在看timeout
和startDelay
操作符
val student = RxHttp.postForm(“/service/…”)
.toClass()
.startDelay(2000)
.timeout(1000)
.await()
以上代码,必定会触发超时异常,因为startDelay,延迟了2000毫秒,而超时时长只有1000毫秒,所以必定触发超时。 但互换下位置,又不一样了,如下:
val student = RxHttp.postForm(“/service/…”)
.toClass()
.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()
.await()
//可直接更新UI
}, {
//异常回调,这里可以拿到Throwable对象
})
以上代码,会在页面销毁时,自动关闭协程,同时自动关闭请求,无需担心内存泄露问题
非FragemntActivity/Fragment/ViewModel环境下
该环境下,我们需要手动创建RxLifeScope
对象,随后调用lanuch
方法开启协程
val job = RxLifeScope().lanuch({
//协程代码块,运行在UI线程
val student = RxHttp.postForm(“/service/…”)
.toClass()
.await()
//可直接更新UI
}, {
//异常回调,这里可以拿到Throwable对象
})
//在合适的时机关闭协程
job.cancel()
以上代码,由于未与生命周期绑定,故我们需要在合适的时机,手动关闭协程,协程关闭,请求也会跟着关闭
监听协程开启/结束回调
以上我们在lanuch
方法,传入协程运行回调及异常回调,我们也可以传入协程开启及结束回调,如下:
rxLifeScope.launch({
//协程代码块
val student = RxHttp.postForm(“/service/…”)
.toClass()
.await()
//可直接更新UI
}, {
//异常回调,这里可以拿到Throwable对象,运行在UI线程
}, {
//开始回调,可以开启等待弹窗,运行在UI线程
}, {
//结束回调,可以销毁等待弹窗,运行在UI线程
})
尾声
评论里面有些同学有疑问关于如何学习material design控件,我的建议是去GitHub搜,有很多同行给的例子,这些栗子足够入门。
有朋友说要是动真格的话,需要NDK以及JVM等的知识,首现**NDK并不是神秘的东西,**你跟着官方的步骤走一遍就知道什么回事了,无非就是一些代码格式以及原生/JAVA内存交互,进阶一点的有原生/JAVA线程交互,线程交互确实有点蛋疼,但平常避免用就好了,再说对于初学者来说关心NDK干嘛,据鄙人以前的经历,只在音视频通信和一个嵌入式信号处理(离线)的两个项目中用过,嵌入式信号处理是JAVA->NDK->.SO->MATLAB这样调用的我原来MATLAB的代码,其他的大多就用在游戏上了吧,一般的互联网公司会有人给你公司的SO包的。
至于JVM,该掌握的那部分,相信我,你会掌握的,不该你掌握的,有那些专门研究JVM的人来做,不如省省心有空看看计算机系统,编译原理。
一句话,平常多写多练,这是最基本的程序员的素质,尽量挤时间,读理论基础书籍,JVM不是未来30年唯一的虚拟机,JAVA也不一定再风靡未来30年工业界,其他的系统和语言也会雨后春笋冒出来,但你理论扎实会让你很快理解学会一个语言或者框架,你平常写的多会让你很快熟练的将新学的东西应用到实际中。
初学者,一句话,多练。
《Android学习笔记总结+移动架构视频+大厂面试真题+项目实战源码》,点击传送门,即可获取!