最近公司比较闲,想到最近听搬砖的砖友说现在 Rxjava + Retrofit2 框架比较火的样子,然后先去看了看Retrofit2,导入到使用还算比较清晰,后来去找了Rxjava一些相关博客读一读,瞬间懵逼了,
总结有以下几个问题:
1、看博客上面使用发现使用起来很麻烦啊,各种函数接函数,我感觉一个简单的功能这样串起来会让别人更难看懂的样子。
2、发现Rxjava提供了很多个函数,使用不同函数处理不同的操作,这样还得去学习和记各种函数,如果是这样并不简单。
3、他有什么优势呢?为什么需要使用它?使用他有什么好处?看上去这么复杂的东西,会让我写代码更快速吗?
最后还是踏上了继续学习Rxjava的道路,在这里会记录下我的全部学习心得,像我这种刚接触的懵逼的砖友可以看看。
我是直接学习的Rxjava2,Rxjava1没有了解就跳过吧。
github是这样描述的: a library for composing asynchronous and event-based programs by using observable sequences. 一个在Java VM上使用可观测的序列来组成异步的、基于事件的程序的库。
我初步学习得到的一个概念是:Rxjava2就实现了观察者 和 被观察者的关系。
在网上看到这张图片形容我觉得对于理解很有帮助
上面一根水管为事件产生的水管,叫它上游吧,下面一根水管为事件接收的水管叫它下游吧。
两根水管通过一定的方式连接起来,使得上游每产生一个事件,下游就能收到该事件, 这里的事件发送的顺序是先1,后2,后3这样的顺序, 事件接收的顺序也是先1,后2,后3的顺序,
上游表示:被观察者(Observable),下游表示:观察者(Observer) 中间连接着就是订阅(subscribe)
下面我们通过Rxjava代码来表现:
在网上看到的使用Rxjava都采用链式操作的写法,我为了好理解所以就分开写了。
链式操作写法如下
这就是初步了解的RxJava,当然Rxjava肯定不止是实现如此简单的逻辑,现在明白了Rxjava一串一串代码的意思,那么Rxjava到底在哪些情况下使用?Rxjava的异步怎么体现呢?现在要去搬砖了。会继续学习....
今天学习(2018/4/27):
观察者(下游) 和 被观察者(上游)方法以及参数和方法的使用规则:
ObservableEmitter: Emitter是发射器的意思,那就很好猜了,这个就是用来发出事件的,它可以发出三种类型的事件,通过调用emitter的onNext(T value)、onComplete()和onError(Throwable error)就可以分别发出next事件、complete事件和error事件。
1、上游可以发送无限个onNext, 下游也可以接收无限个onNext.
2、当上游发送了一个onComplete后, 上游onComplete之后的事件将会继续发送, 而下游收到onComplete事件之后将不再继续接收事件.
3、当上游发送了一个onError后, 上游onError之后的事件将继续发送, 而下游收到onError事件之后将不再继续接收事件.
4、上游可以不发送onComplete或onError.
5、最为关键的是onComplete和onError必须唯一并且互斥, 即不能发多个onComplete, 也不能发多个onError, 也不能先发一个onComplete, 然后再发一个onError, 反之亦然
6、注意关于onComplete和onError唯一并且互斥这一点 是手动控制的,由自己主动调用和不调用
Disposable参数 当调用它的dispose()方法时, 它就会将两根管道切断, 从而导致下游收不到事件.但是上游的还是会执行后续的发送,只是下游无法收到。
学习RxJava强大的线程控制,是不是表示异步?(答案是可以切换不同线程)
正常情况下, 上游和下游是工作在同一个线程中的, 也就是说上游在哪个线程发事件, 下游就在哪个线程接收事件,比如我在Activity的OnCreat方法中定义,那么他属于主线程。
但是我文章开头就疑问,他的意义何在?做网络请求 结合Retrofit使用肯定是要用到异步的。
那么如何在子线程中做耗时的操作, 然后回到主线程中来操作UI呢?
用上面图来分析,我们用黄色水管表示子线程, 深蓝色水管表示主线程.
要达到这个目的, 我们需要先改变上游发送事件的线程, 让它去子线程中发送事件, 然后再改变下游的线程, 让它去主线程接收事件. 通过RxJava内置的线程调度器可以很轻松的做到这一点. 接下来看一段代码:
同之前的代码就增加了二句:
.subscribeOn(Schedulers.newThread())
.observeOn(AndroidSchedulers.mainThread())
那么这二句是什么意思呢?第一句是设置被观察者(发送者)在子线程中执行,第二句的意思是让观察者(接收者)在主线程执行。
多次指定上游的线程只有第一次指定的有效, 也就是说多次调用subscribeOn() 只有第一次的有效, 其余的会被忽略.
多次指定下游的线程是可以的, 也就是说每调用一次observeOn() , 下游的线程就会切换一次.(那么问题来了多次指定线程能干什么用?执行的顺序是什么样的?)
接下来学习的是如果需要连续调用二个接口。比如用户先注册再登录.
这里就会用到observeOn()调用多次分别执行一个回调,顺序是按代码顺序。
要先了解下几个操作符
1.Map操作符
它的作用就是对上游发送的每一个事件应用一个函数, 使得每一个事件都按照指定的函数去变化
2.FlatMap操作符、concatMap操作符
FlatMap将一个发送事件的上游Observable变换为多个发送事件的Observables,然后将它们发射的事件合并后放进一个单独的Observable里.
注意:flatMap并不保证事件的顺序, 如果需要顺序 使用concatMap
直接上代码
ZIP操作符:
Zip通过一个函数将多个Observable(上游)发送的事件结合到一起,然后发送这些组合到一起的事件. 它按照严格的顺序应用这个函数。它只发射与发射数据项最少的那个Observable一样多的数据。
最终下游收到的事件数量 是和上游中发送事件最少的那一根水管的事件数量 相同. 这个也很好理解, 因为是从每一根水管 里取一个事件来进行合并, 最少的 那个肯定就最先取完 , 这个时候其他的水管尽管还有事件 , 但是已经没有足够的事件来组合了, 因此下游就不会收到剩余的事件了.
注意:当被订阅者的二个事件在同一个线程的情况下,会先发送第一个事件发送完,再发送第二个事件,再合并。如果要2个事件同时发,可以把二个线程放在不同的线程。
实践:比如一个界面需要展示用户的一些信息, 而这些信息分别要从两个服务器接口中获取, 而只有当两个都获取到了之后才能进行展示, 这个时候就可以用Zip了。
Backpressure 操作符的使用(上游和下游的发送事件和接收事件速度不一样的情况,后续为了解决这一问题还有一个知识点Flowable)。
当Observable 和 Observer 不在同一个线程的时候(异步),Observable连续发送很多个时(比如定义一个for循环连续发送),发送到一个中间存储空间,然后Observer从这个中间空间取,当Observer接受缓慢时候,水缸就会爆满、就会出现内存持续增加的问题。所以关联产生了Backpressure的使用。
sample操作符, 简单做个介绍, 这个操作符每隔指定的时间就从上游中取出一个事件发送给下游.(这里取应该是指的是 先放到中间存储空间等Observer来取) 这样会导致数据丢失
这里我们学习下Flowable的使用(上面学习Observable和Observer,其实Flowable跟上面的二个功能是一样的,貌似很多人学习了Flowable后,都会选择使用后者。)
之前我们所的上游和下游分别是Observable和Observer, 这次不一样的是上游变成了Flowable, 下游变成了Subscriber, 但是水管之间的连接还是通过subscribe(), 我们来看看最基本的用法吧,代码不贴了。
还发现了个比较实用的。利用RxJava内部的RxJavaPlugins来做这么一个骚操作。(骚的操作就是在网络请求的时候,对错误进行统一处理。刚开始看我是一脸懵逼)