RxJava常用操作符官方文档翻译及Kotlin示例(1)

Rxjava2 可谓是日常开发中的利器,特别是在异步任务中更能发挥作用。响应式编程以及流式api的良好支持,给予了更好的编码体验。越来越多开发者渐渐用起来了。学习rxjava2最好的地方无外乎官方文档,详细且完整。以下结合官方文档和我自己的理解以及例子,解释各个操作符的用法,给各位以及我自己作一篇参考。

怎么用Rxjava2

要使用RxJava,需要先创建Observables(发出数据项),以各种方式转换这些Observable以获取所需要的精确数据项(通过使用Observable运算符),然后观察并响应这些需要的项目序列(通过实现观察者)
或者订阅者,然后将它们订阅到最终的变换后的Observables)。

Creating Observables 创建操作符

just

通过获取预先存在的对象并在订阅时将该特定对象发布给下游使用者来构造反应类型。为方便起见,存在2到9个参数的重载,这些对象(具有相同的常见类型)将按指定的顺序发出。就像From类似,但请注意From将传入一个数组或一个iterable或类似的东西来取出要发出的项目,而Just只是简单地发出数组或者迭代器。

请注意,如果将null传递给Just,它将返回一个Observable,它将null作为项发出。不要错误地假设这将返回一个空的Observable(一个根本不发出任何项目)。为此,需要使用Empty运算符。


just
    fun testOpJust() {
        val arr = arrayOf("mary", "tom", "ben", "lisa", "ken")
        Observable.fromArray(arr).filter { it.size > 3 }.map { it + "s" }.subscribe(System.out::println)

        val list = arrayListOf("mary", "tom", "ben", "lisa", "ken")
        Observable.just(list).forEach { it -> System.out.println(it + "s") }

        list.stream().filter { it -> it.length > 3 }.map { "$it s" }.forEach(System.out::println)
    }

from

根据预先存在的源或生成器类型构造序列。当使用Observable时,如果使用的所有数据都可以表示为Observables,而不是Observables和其他类型的混合,则可以更方便。这允许使用一组运算符来控制数据流的整个生命周期。例如,Iterables可以被认为是一种的Observable;作为一种始终只发出单一项目的Observable。通过将这些对象显式转换为Observable,可以将它们作为对等体与其他Observable进行交互。因此,大多数ReactiveX实现都具有允许将特定于语言的对象和数据结构转换为Observable的方法。

注意:这些静态方法使用后缀命名约定(即,在方法名称中重复参数类型)以避免重载解析模糊。

from
fromIterable

从java.lang.Iterable源(例如Lists,Sets或Collections或custom Iterables)发出信号,然后完成序列。

可用于 Flowable ,Observable

fromArray

发信号通知给定数组的元素,然后完成序列。
可用于Flowable,Observable

注意:RxJava不支持原始数组,只支持(通用)引用数组。

fun testOpFrom(){
        val list = arrayListOf<Int>(1,2,3,4,5,6)
        Observable.fromIterable(list).subscribe(System.out::println)

        Observable.fromArray(1,2,3,4,5,6).subscribe(System.out::println)

    }
fromCallable

当消费者订阅时,调用给定的java.util.concurrent.Callable并将其返回值(或抛出的异常)转发给该使用者。

可用于:Observable,Flowable,Maybe,Single,Completable

备注:在Completable中,忽略实际返回值,并且Completable完成。

       Observable.fromCallable<String> {
            "hello"
        }.subscribe(System.out::println)

        Completable.fromCallable{
            "complatable from callable"
        }.subscribe {
            System.out.println("complete")
        }

fromAction

当消费者订阅时,调用给定的io.reactivex.function.Action并且消费者完成或接收Action抛出的异常。

可用于: Maybe,Completable

   Maybe.fromAction<String>{
            System.out.println("maybe from action")
        }.subscribe(System.out::println)

以下标星先不多做解释,用得不多

*fromRunnable

*fromFuture

*from{reactive type}

将另一种反应类型包裹或转换为目标反应类型。具有以下签名模式的各种反应类型中提供以下组合:targetType.from {sourceType}()

*注意:并非所有可能的转换都是通过from {reactive type}方法系列实现的。查看to {reactive type}方法系列以获得进一步的转换可能性。

注意:fromAction和fromRunnable之间的区别在于Action接口允许抛出已受检的异常,而java.lang.Runnable则不然。

error

可用于Observable,Flowable,Maybe,Single,Completable

通过java.util.concurrent.Callable向消费者发出预先存在或生成的错误信号。

  fun testOpError(){
        Observable.error<Throwable>(IOException(""))
                .subscribe({
                    System.out.print("不会打印吧")
                },{
                    it.printStackTrace()
                },{
                    System.out.println("也不会打印")
                })
    }

一个典型的用例是使用onErrorResumeNext有条件地映射或抑制链中的异常:

   /**
     * 抑制链上发生的异常
     */
    @Test
    fun testOpOnErrorResumeNext() {
        val observable = Observable.fromCallable {
            if (Math.random() < 0.5f) {
                throw IllegalArgumentException()
            }
            throw IOException()
        }

        observable.onErrorResumeNext(Function {
            if (it is IllegalArgumentException) {
                Observable.empty()
            } else {
                Observable.error(it)
            }
        }).subscribe({
            System.out.println("nothing")
        },{
            it.printStackTrace()
        },{
            System.out.println("empty")
        })
    }

这个onErrorResumeNext 厉害了,可以说之前一直不太明白怎么很好的处理。通过此操作符可以抑制错误的传递,本来如果subscribe发生了错误会触发onError回调。事实上可能发生了错误,需要不处理或者抑制产生。在onErrorResumeNext的function参数中,可以根据错误类型返回处理流程。

  • empty 这种类型的源在订阅后立即表示完成。
    可用于Observable,Flowable,Maybe,Single,Completable

示例可见onErrorResumeNext的例子

empty

empty发送直接表示完成,就是订阅者直接调用onComplete回调。onNext 不会执行

  • never 这种类型的源不会发出任何onNext,onSuccess,onError或onComplete的信号。这种类型的反应源可用于测试或“禁用”组合子操作符中的某些源。

可用于Observable,Flowable,Maybe,Single,Completable

不会对订阅者的任何回调进行调用。禁用也可理解,比如发送了错误,都不往下执行

  • interval 定期生成无限的,不断增加的数字(Long类型)。intervalRange变体生成有限数量的此类数字。

可用于Observable,Flowable

interval
    fun testOpInterval(){
        Observable.interval(1,TimeUnit.SECONDS)
                .onErrorResumeNext(Function { 
                    Observable.error(it)
                })
                .subscribe({
                    if (it.rem(5) == 0L) {
                        System.out.println("tick")
                    } else {
                        System.out.println("tock")
                    }
                },{
                    it.printStackTrace()
                },{
                    System.out.println("interval complete")
                })
    }
  • Timer运算符创建一个Observable,在指定的一段时间后发出一个特定项。


    Timer

也就是说在给定的时间之后发送事件

  • range 为每个消费者生成一系列值。range()方法生成Integers,rangeLong()生成Longs。Range运算符按顺序发出一系列顺序整数,您可以在其中选择范围的起点及其长度。

可用于 Observable,Flowable

range
    fun testOpRange(){
        val s = "test range operation now"
        Observable.range(0,s.length- 3)
                .map { "${s[it]} in range"}
                .subscribe {
                    System.out.println(it)
                }
    }

发出一系列值,参数为起点,和长度。

  • generate 创建一个冷,同步和有状态的值生成器。

可用于Observable,Flowable

create
   @Test
    fun testOpGenerate(){
        val start = 1
        val increaseValue = 2
        Observable.generate<Int,Int>(Callable<Int> {
            start
        }, BiFunction<Int, Emitter<Int>,Int> {
            t1, t2 ->
            t2.onNext(t1 + increaseValue)
            t1 + increaseValue
        }).subscribe {
            System.out.println("generate value : $it")
        }
    }

不太明白干啥的,具体应用场景。只是一直不间断的产生值

Filtering Observables 过滤Observable

过滤操作是非常常用且重要的,而且相关的操作符也很多

Debounce

可用于Observable,Flowable

删除响应源发出的项目,在给定的超时值到期之前,这些项目后面跟着更新的项目。计时器重置每次发射。此运算符会跟踪最近发出的项目,并且仅在有足够的时间过去而没有源发出任何其他项目时才会发出此项目。

按照我得理解就是debounde传入了超时值,在该时间之内如果多次发射,取离超时值最近得值。既然又超时那么也应该又开始时间,开始时间就是一组发射最开始值得时间,这一组发射得值的时的差是在debounce超时时间之内。

// Diagram:
// -A--------------B----C-D-------------------E-|---->
//  a---------1s
//                 b---------1s
//                      c---------1s
//                        d---------1s
//                                            e-|---->
// -----------A---------------------D-----------E-|-->

   fun testOpDebounce(){
        Observable.create<String>{
            it.onNext("A")
            Thread.sleep(1_500)
            it.onNext("B")
            Thread.sleep(500)
            it.onNext("C")
            Thread.sleep(250)
            it.onNext("D")
            Thread.sleep(2_000)
            it.onNext("E")
        }.debounce(1,TimeUnit.SECONDS)
                .subscribe(System.out::println)
    }

distinct

可用于Observable Flowable
通过仅发出与先前项目相比不同的项目来过滤反应源。可以指定io.reactivex.functions.Function,将源发出的每个项目映射到一个新值中,该值将用于与先前的映射值进行比较。Distinct运算符通过仅允许尚未发出的项目来过滤Observable。在一些实现中,存在允许调整两个项被视为“不同”的标准的变体。在一些实施例中,存在操作符的变体,其仅将项目与其前一个项目进行比较以获得更精确的比较,从而仅过滤连续的重复项目,序列中的项目。

    fun testOpDistinct(){
        Observable.fromArray(1,2,3,3,4,5)
                .distinct()
                .subscribe(System.out::println)

        // 用来过滤序列中一组值前后是否相同得值
        Observable.fromArray(1,1,2,3,2)
                .distinct { "呵呵" }
                .subscribe(System.out::println)
    }

重载的方法,传入keySelectro ,作用是对每个元素应用方法得到得新得值,再决定怎么去重

distinctUntilChanged

可用于Observable Flowable
通过仅发出与其前一个元素相比较不同的项目来过滤反应源。可以指定io.reactivex.functions.Function,将源发出的每个项目映射到一个新值中,该值将用于与先前的映射值进行比较。或者,可以指定io.reactivex.functions.BiPredicate作为比较器函数来比较前一个。

        Observable.fromArray(1,2,3,3,4,5)
//                .distinctUntilChanged()
                .distinctUntilChanged { t1, t2 ->
                    t1 == t2
                }
                .subscribe(System.out::println)

可以说是distinct的加强版,多了一个可以传入比较器的重载方法

elementAt

课用于Flowable,Observable
在来自反应源的一系列发射的数据项中,以指定的从零开始的索引发出单个项目。如果指定的索引不在序列中,则可以指定将发出的默认项。

简单说就是按照发出项的次序获取指定的位置的元素

     Observable.fromArray(1,2,3,3,4,5)
                .elementAt(2)
                .subscribe(System.out::println)

elementAtOrError

filter

可用于Observable,Flowable,Maybe,Single
通过仅发出满足指定函数的项来过滤由反应源发出的项。

过滤偶数
 Observable.fromArray(1,2,3,3,4,5)
                .filter {
                    it.rem(2) == 0
                }
                .subscribe(System.out::println)}

first

可用于Flowable,Observable
仅发出反应源发出的第一个项目,或者如果源完成而不发出项目则发出给定的默认项目。这与firstElement的不同之处在于此运算符返回Single,而firstElement返回Maybe。

   Observable.fromArray(1,2,3,3,4,5)
                .first(-1)
                .subscribe(Consumer<Int> {
                    System.out.println("onNext :$it")
                })
                
                      Observable.fromArray(1,2,3,3,4,5)
                .firstElement()
                .subscribe {
                    System.out.println("onNext :$it")
                }

firstOrError

仅发出响应源发出的第一个项目,或者如果源完成而不发出项目则发出java.util.NoSuchElementException信号。

ignoreElement

可用于Maybe Single
忽略Single或Maybe源发出的单个项目,并返回一个Completable,它仅从源中发出错误或完成事件的信号。


ignoreElement
 Maybe.timer(1L,TimeUnit.SECONDS)
                .ignoreElement()
                .doOnComplete {
                    System.out.println("done")
                }
                .blockingAwait()

ignoreElements

忽略Single或Maybe源发出的单个项目,并返回一个Completable,它仅从源中发出错误或完成事件的信号。

 Observable.timer(1L,TimeUnit.SECONDS)
                .ignoreElements()
                .doOnComplete {
                    System.out.println("completed")
                }
                .blockingAwait()

last

可用于Observable,Flowable

仅发出反应源发出的最后一个项目,或者如果源完成而不发出项目则发出给定的默认项目。这与lastElement的不同之处在于此运算符返回Single,而lastElement返回Maybe。

   Observable.fromArray(1,2,3,3,4,5)
                .last(-1)
                .subscribe(Consumer<Int>{
                    System.out.println("last $it")
                })

lastElement

  Observable.fromArray(1,2,3,3,4,5)
                .lastElement()
                .subscribe(Consumer<Int>{
                    System.out.println("last $it")
                })

lastOnError

仅发出响应源发出的最后一项,或者如果源完成而不发出项,则发出java.util.NoSuchElementException信号。

ofType

可用于Flowable,Observable,Maybe
通过仅发出指定类型的项目来过滤反应源发出的项目。

 Observable.fromArray(1,2.1f,3,3,4,5)
                .ofType(Int::class.java)
                .subscribe(Consumer<Int>{
                    System.out.println("last $it")
                })

sample

可用于Observable Flowable
通过仅在周期性时间间隔内发出最近发出的项目来过滤反应源发出的项目。


 Observable.create<String> {
            it.onNext("A")
            Thread.sleep(1_000)

            it.onNext("B")
            Thread.sleep(300)

            it.onNext("C")
            Thread.sleep(700)

            it.onNext("D")
            it.onComplete()
        }.sample(1,TimeUnit.SECONDS)
                .blockingSubscribe(System.out::println)

skip

删除响应源发出的前n个项目,并发出剩余项目。您可以通过使用Skip运算符修改Observable来忽略Observable发出的前n个项目,并仅参加之后的项目。

 Observable.fromArray("hehe",2.1f,3,3,4,5)
//                .ofType(String::class.java)
                .skip(3)
                .subscribe {
                    System.out.println(it)
                }

skipLast

丢弃反应源发出的最后n个项目,并发出剩余的项目。

take

可用于Flowable Observable
仅发出反应源发出的前n项。

     Observable.fromArray("hehe",2.1f,3,3,4,5)
                .take(2)
                .subscribe(System.out::println)

takeLast

可用于Flowable Observable
仅发出反应源发出的最后n个项目。

throttleFirst

可用于Flowable Observable

跟debounce有些相似,是取时间范围内第一个,在点击事件过滤很常用

在指定持续时间的连续时间窗口期间仅发出由反应源发出的第一个项目。

 Observable.create<String> {
            it.onNext("A")
            Thread.sleep(300)

            it.onNext("B")
            Thread.sleep(400)
        }.throttleFirst(1,TimeUnit.SECONDS)
                .subscribe(System.out::println)

throttleLast

可用于Observable,Flowable
在指定持续时间的连续时间期间仅发出由反应源发出的最后一个项目。跟throttleFirst相反,取最后一个值

throttleWithTimeout

跟debounce的别名

    public final Observable<T> throttleWithTimeout(long timeout, TimeUnit unit) {
        return debounce(timeout, unit);
    }

timeout

从Observable或Flowable源发出项目,但如果在从上一项开始的指定超时持续时间内未发出下一项,则以java.util.concurrent.TimeoutException终止。对于Maybe,Single和Completable,指定的超时持续时间指定等待成功或完成事件到达的最长时间。如果Maybe,Single或Completable在给定时间内没有完成,将发出java.util.concurrent.TimeoutException。

   Observable.create<String>{
            it.onNext("A")
            Thread.sleep(600)

            it.onNext("B")
            Thread.sleep(1_500)

            it.onNext("C")
            Thread.sleep(500)
        }.subscribeOn(Schedulers.io())
                .subscribe({
                    System.out.println(it)
                },{
                    it.printStackTrace()
                })

捕获处理

一下为Kotlin编写的代码,可以看到在发生错误的情况下,通过onError() 抛出了错误,并且需要在订阅者,第二个参数传入,处理错误的回调。

    fun testErrorHandle() {
        Observable.create<String> {
            it.onNext("start")
            Thread {
                try {
                    System.out.println("start open ...")
                    it.onNext("start open ...")
                    val stream = URL("https://www.baidu.com").openStream()
                    System.out.println("after url ...")
                    it.onNext("after url")
                    val br = stream.bufferedReader()
                    if (!it.isDisposed) {
                        var text = br.readText()
                        it.onNext(text)
                    }
                    stream.close()
                    br.close()
                    it.onNext("after open ...")
                    if (!it.isDisposed) {
                        it.onComplete()
                    }
                }catch (e : java.lang.Exception) {
                    System.out.println(e)
                    e.printStackTrace()
                    it.onError(e)
                }
            }.start()
        }.subscribe(System.out::println) {
            it.printStackTrace()
            System.out.println("what the fuck")
        }
    }

Observable通常不会抛出异常。相反,它会通过使用onError通知终止Observable序列来通知任何观察者发生了不可恢复的错误。

这有一些例外。例如,如果onError()调用本身失败,Observable将不会尝试通过再次调用onError来通知观察者,但会抛出RuntimeException,OnErrorFailedException或OnErrorNotImplementedException。

从onError通知中恢复的技术

因此,不是捕获异常,而是观察者或操作者应该更通常地响应异常的onError通知。还有各种Observable运算符可用于对来自Observable的onError通知作出反应或从中恢复。例如,可以使用运算符:

  1. 吞下错误并切换到备份Observable以继续序列
  2. 吞下错误并发出默认项
  3. 吞下错误并立即尝试重启失败的Observable
  4. 吞下错误并尝试在一些退避间隔后重新启动失败的Observable

可以使用错误处理运算符中描述的运算符来实现这些策略。

吞下的意思,应该是不处理异常

RxJava特定的异常以及如何处理它们

CompositeException
这表明发生了多个异常。可以使用异常的getExceptions()方法来检索构成组合的各个异常。

MissingBackpressureException
这表示试图将过多发出数据项应用于它的Observable。有关背压(https://github.com/ReactiveX/RxJava/wiki/Backpressure)的Observable的解决方法,请参阅Backpressure。

OnErrorFailedException
这表明Observable试图调用其观察者的onError()方法,但该方法本身引发了异常。

OnErrorNotImplementedException
这表明Observable试图调用其观察者的onError()方法,但是没有这样的方法存在。可以通过修复Observable以使其不再达到错误条件,通过在观察者中实现onError处理程序,或通过使用本页其他地方描述的其中一个运算符到达观察者之前截获onError通知来消除此问题。。

OnErrorThrowable
观察者将这种类型的throwable传递给他们的观察者的onError()处理程序。此变量的Throwable包含有关错误的更多信息以及错误发生时系统的Observable特定状态,而不是标准Throwable。

参考资料

官网文档

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,684评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,143评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,214评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,788评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,796评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,665评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,027评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,679评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 41,346评论 1 299
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,664评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,766评论 1 331
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,412评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,015评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,974评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,203评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,073评论 2 350
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,501评论 2 343

推荐阅读更多精彩内容