RxJava 2.0有什么不同(译)

来源:互联网 发布:java热替换jar包文件 编辑:程序博客网 时间:2024/05/18 02:33

ReactiveX 于2016.10.29 发布了正式版RxJava 2.0.0,但到我写本文章为止,还没有发现谁完整的翻译了官方的这篇文档 What’s-different-in-2.0。

秉着旧事物迟早被新事物替代的想法,于是我用我没过6级的英语咬牙翻译下这篇文章,希望能帮助年轻的司机。但鉴于本人水平有限,翻译得不好,如果各位大神发现哪里写错了,欢迎发邮件通知我,我会在第一时间改正,本人邮箱:86839868@qq.com 

关于我们

作者: 宇不语 
个人网站: www.ittianyu.com 
个人博客: blog.csdn.net/qq_35064774 
Github: github.com/ittianyu 
本文地址:点这里

开始

RxJava 2.0 已经按照Reactive-Streams specification规范完全的重写了。2.0 已经独立于RxJava 1.x而存在。

因为Reactive-Streams有一个不同的构架,它改变了一些以往RxJava的用法。这份文档尝试去总结所发生的变化,并描述如何把1.x的代码改写成符合2.x规则的代码。

这个页面是为本库用户写的,这将会有一个分界页面,专门留给为RxJava库开发者以及那些希望为2.x版本开发自定义操作符的用户

Maven 地址和基础包

为了让 RxJava 1.x 和 RxJava 2.x 相互独立,我们把RxJava 2.x 被放在了maven io.reactivex.rxjava2:rxjava:2.x.y 下,类放在了 io.reactivex 包下

用户从 1.x 切换到 2.x 时需要导入的相应的包,但注意不要把1.x和2.x混淆了。

Javadoc

Java 文档

官方2.x的 Java 文档 http://reactivex.io/RxJava/2.x/javadoc/

Nulls

RxJava 2x 不再支持 null 值,如果传入一个null会抛出 NullPointerException

Observable.just(null);Single.just(null);Observable.fromCallable(() -> null)    .subscribe(System.out::println, Throwable::printStackTrace);Observable.just(1).map(v -> null)    .subscribe(System.out::println, Throwable::printStackTrace);
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

这意味着 Observable<Void> 不再发射任何值,而只是正常结束或者抛出异常。API 设计者可以定义 Observable<Object> 这样的观察者, 因为并不确定具体是什么类型的 Object。例如,如果你需要一个 signaller-like ,你可以定义一个共享的枚举类型,它是一个单独的实例onNext‘d:

enum Irrelevant { INSTANCE; }Observable<Object> source = Observable.create((ObservableEmitter<Object> emitter) -> {   System.out.println("Side-effect 1");   emitter.onNext(Irrelevant.INSTANCE);   System.out.println("Side-effect 2");   emitter.onNext(Irrelevant.INSTANCE);   System.out.println("Side-effect 3");   emitter.onNext(Irrelevant.INSTANCE);});source.subscribe(e -> { /* Ignored. */ }, Throwable::printStackTrace);
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14

Observable 和 Flowable

在RxJava 0.x中关于介绍backpressure部分有一个小小的遗憾,那就是没有用一个单独的类,而是使用了Observable。 主要的背压问题是有很多很火的代码,像UI events,不能合理的背压,导致了无法意料的 MissingBackpressureException

我们试图在 2.x 中纠正这个问题。因此我们把io.reactivex.Observable 设计成非背压的,并增加一个新的io.reactivex.Flowable 去支持背压。

好消息是操作符的名字几乎没有改动。坏消息是当你执行’organize imports’时必须要格外的小心,它可能无意的给你选择一个非背压的io.reactivex.Observable 。

Single

2.x 的Single类可以发射一个单独onSuccess 或 onError消息。它现在按照Reactive-Streams规范被重新设计,SingleObserver改成了如下的接口。

interface SingleObserver<T> {    void onSubscribe(Disposable d);    void onSuccess(T value);    void onError(Throwable error);}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 1
  • 2
  • 3
  • 4
  • 5

并遵循协议 onSubscribe (onSuccess | onError)?.

Completable

Completable大部分和以前的一样。因为它在1.x的时候就是按照Reactive-Streams的规范进行设计的。

命名上有些变化, 
rx.Completable.CompletableSubscriber 变成了 io.reactivex.CompletableObserver 和 onSubscribe(Disposable):

interface CompletableObserver<T> {    void onSubscribe(Disposable d);    void onComplete();    void onError(Throwable error);}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 1
  • 2
  • 3
  • 4
  • 5

并且仍然遵循协议 onSubscribe (onComplete | onError)?.

Maybe

RxJava 2.0.0-RC2 介绍了一个新的类型 Maybe 。从概念上来说,它是Single 和 Completable 的结合体。它可以发射0个或1个通知或错误的信号。

Maybe类结合了MaybeSourceMaybeObserver<T>作为信号接收接口,同样遵循协议onSubscribe (onSuccess | onError | onComplete)?。因为最多有一个元素被发射,Maybe没有背压的概念。

这意味着调用onSubscribe(Disposable)请求可能还会触发其他 onXXX方法。和Flowable不同,如果那有一个单独的值要发射,那么只有onSuccess被调用,onComplete不被调用。

这个新的类,实际上和其他Flowable的子类操作符一样可以发射0个或1个序列。

Maybe.just(1).map(v -> v + 1).filter(v -> v == 1).defaultIfEmpty(2).test().assertResult(2);
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

Base reactive interfaces

基础reactive接口

按照Reactive-Streams风格的Flowable实现了 Publisher<T>接口,其他基础类也实现了类似的基础接口

interface ObservableSource<T> {    void subscribe(Observer<? super T> observer);}interface SingleSource<T> {    void subscribe(SingleObserver<? super T> observer);}interface CompletableSource {    void subscribe(CompletableObserver observer);}interface MaybeSource<T> {    void subscribe(MaybeObserver<? super T> observer);}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15

因此,很多操作符需要从用户接收Publisher 和 XSource的一些基础的类型。

Flowable<R> flatMap(Function<? super T, ? extends Publisher<? extends R>> mapper);Observable<R> flatMap(Function<? super T, ? extends ObservableSource<? extends R>> mapper);
  • 1
  • 2
  • 3
  • 1
  • 2
  • 3

通过Publisher作为输入,你可以组合其他的遵从Reactive-Streams规范的库,而不需要包裹或把它们转换成Flowable

如果一个操作符必须要提供一个基础类,那么用户将会收到一个完整的基础类。

Flowable<Flowable<Integer>> windows = source.window(5);source.compose((Flowable<T> flowable) ->     flowable    .subscribeOn(Schedulers.io())    .observeOn(AndroidSchedulers.mainThread()));
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

Subjects 和 Processors

在Reactive-Streams规范中,Subject类似于行为,即消费者和提供者的事件在同一时间发生。随着Observable/Flowable的分离,支持背压的类都是遵从Reactive-Streams规范的FlowableProcessor<T>的子类。一个关于Subject重要的变化是它们不再支持T -> R这样的转换。

在 2.x 中, io.reactivex.subjects.AsyncSubjectio.reactivex.subjects.BehaviorSubjectio.reactivex.subjects.PublishSubjectio.reactivex.subjects.ReplaySubject 和 io.reactivex.subjects.UnicastSubject 不支持背压。

io.reactivex.processors.AsyncProcessorio.reactivex.processors.BehaviorProcessorio.reactivex.processors.PublishProcessorio.reactivex.processors.ReplayProcessor 和io.reactivex.processors.UnicastProcessor 支持背压。 BehaviorProcessor 和 PublishProcessor 不能协同请求下级的订阅者,如果下游不能保存,则会发射一个MissingBackpressureException异常。其他XProcessor类支持对下游订阅者背压,但是当被订阅源时,它们会无限制的消费。

其他类

rx.observables.ConnectableObservable 现在是io.reactivex.observables.ConnectableObservable<T> 和 io.reactivex.flowables.ConnectableFlowable<T>

GroupedObservable

rx.observables.GroupedObservable 现在是io.reactivex.observables.GroupedObservable<T> 和io.reactivex.flowables.GroupedFlowable<T>.

在1.x中,你可以用GroupedObservable.from()创建一个实例。在2.x中,所有实例都直接继承了GroupedObservable,因此这个工厂方法不再可用; 现在整个类都是抽象的。

不过你可以继承类然后添加你自定义的subscribeActual行为来达到1.x中相似的功能。

class MyGroup<K, V> extends GroupedObservable<K, V> {    final K key;    final Subject<V> subject;    public MyGroup(K key) {        this.key = key;        this.subject = PublishSubject.create();    }    @Override    public T getKey() {        return key;    }    @Override    protected void subscribeActual(Observer<? super T> observer) {        subject.subscribe(observer);    }}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20

功能接口

1.x 和 2.x 是跑在Java 6以上的虚拟机的,所以我们不能使用Java8的功能接口(functional interfaces),比如java.util.function.Function。但我们可以按照这个例子来定义自己的功能接口(functional interfaces)。

一个值得注意的区别是所有的功能接口(functional interfaces)都定义了throws Exception。这对于consumers 和 mappers 来说是一个巨大的便利,你不需要用try-catch捕获异常。

Flowable.just("file.txt").map(name -> Files.readLines(name)).subscribe(lines -> System.out.println(lines.size()), Throwable::printStackTrace);
  • 1
  • 2
  • 3
  • 1
  • 2
  • 3

如果文件不存在或者不可读,结尾的consumer会直接输出IOException。你可以直接调用Files.readLines(name)而不需要捕获异常。

Actions

为了减少组件数量,2.x中没有定义Action3-Action9ActionN

保留的action接口按照java 8 functional风格命名。 无参数的Action0 被操作符io.reactivex.functions.ActionScheduler代替。Action1被重命名为ConsumerAction2 被重命名为BiConsumer。 ActionN 被Consumer<Object[]> 代替。

Functions

我们按照Java 8的命名风格定义了io.reactivex.functions.Function 和io.reactivex.functions.BiFunction, 把Func3 - Func9 分别改成了 Function3 - Function9 。FuncNFunction<Object[], R>代替。

此外,操作符不再使用Func1<T, Boolean>但原始返回类型为Predicate<T>

io.reactivex.functions.Functions类提供了常见的转换功能Function<Object[], R>

Subscriber

Reactive-Streams规范有自己的Subscriber。这个接口是轻量级的,并且把请求管理和取消机制整合进了一个单独的接口org.reactivestreams.Subscription,而不是分别用rx.Producer 和 rx.Subscription。这就可以用比1.x中rx.Subscriber更少的内部状态来创建一个stream consumers。

Flowable.range(1, 10).subscribe(new Subscriber<Integer>() {    @Override    public void onSubscribe(Subscription s) {        s.request(Long.MAX_VALUE);    }    @Override    public void onNext(Integer t) {        System.out.println(t);    }    @Override    public void onError(Throwable t) {        t.printStackTrace();    }    @Override    public void onComplete() {        System.out.println("Done");    }});
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21

由于命名冲突,把rx 包改成org.reactivestreams。此外org.reactivestreams.Subscriber 不能从外面添加、取消或请求。

为了弥补这一空缺,我们为Flowable定义了抽象类DefaultSubscriberResourceSubscriber 和 DisposableSubscriber 分别提供了类似于rx.Subscriber的资源跟踪支持,并且可以从外面取消 dispose():

ResourceSubscriber<Integer> subscriber = new ResourceSubscriber<Integer>() {    @Override    public void onStart() {        request(Long.MAX_VALUE);    }    @Override    public void onNext(Integer t) {        System.out.println(t);    }    @Override    public void onError(Throwable t) {        t.printStackTrace();    }    @Override    public void onComplete() {        System.out.println("Done");    }};Flowable.range(1, 10).delay(1, TimeUnit.SECONDS).subscribe(subscriber);subscriber.dispose();
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25

注意,由于Reactive-Streams的兼容性,方法onCompleted被重命名为onComplete

因为1.x中,Observable.subscribe(Subscriber)返回Subscription,用户经常添加SubscriptionCompositeSubscription中,例如:

CompositeSubscription composite = new CompositeSubscription();composite.add(Observable.range(1, 5).subscribe(new TestSubscriber<Integer>()));
  • 1
  • 2
  • 3
  • 1
  • 2
  • 3

由于Reactive-Streams规范,Publisher.subscribe无返回值。为了弥补这一点,我们增加了E subscribeWith(E subscriber)方法。因为在2.x中ResourceSubscriber 直接实现了Disposable,所以代码可以这样写。

CompositeDisposable composite2 = new CompositeDisposable();composite2.add(Flowable.range(1, 5).subscribeWith(subscriber));
  • 1
  • 2
  • 3
  • 1
  • 2
  • 3

在onSubscribe/onStart中调用request

注意,在Subscriber.onSubscribeResourceSubscriber.onStart中调用request(n)将会立即调用onNext,实例代码如下:

Flowable.range(1, 3).subscribe(new Subscriber<Integer>() {    @Override    public void onSubscribe(Subscription s) {        System.out.println("OnSubscribe start");        s.request(Long.MAX_VALUE);        System.out.println("OnSubscribe end");    }    @Override    public void onNext(Integer v) {        System.out.println(v);    }    @Override    public void onError(Throwable e) {        e.printStackTrace();    }    @Override    public void onComplete() {        System.out.println("Done");    }});
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24

This will print: 
将会打印:

OnSubscribe start123DoneOnSubscribe end
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

当你在onSubscribe/onStart中做了一些初始化的工作,而这些工作是在request后面时,会出现一些问题,在onNext执行时,你的初始化工作的那部分代码还没有执行。为了避免这种情况,请确保你调用request时,已经把所有初始化工作做完了。

这个行为不同于1.x中的 request要经过延迟的逻辑直到上游的Producer到达时。在2.x中,总是Subscription先传递下来,90%的情况下没有延迟请求的必要。

Subscription

在RxJava 1.x中,接口rx.Subscription负责流和资源的生命周期管理,即退订和释放资源,例如scheduled tasks。Reactive-Streams规范用这个名称指定source和consumer之间的关系: org.reactivestreams.Subscription 允许从上游请求一个正数,并支持取消。

为了避免名字冲突,1.x的rx.Subscription被改成了 io.reactivex.Disposable

因为Reactive-Streams的基础接口org.reactivestreams.Publisher 定义subscribe()为无返回值,Flowable.subscribe(Subscriber)不再返回任何Subscription。其他的基础类型也遵循这种规律。

在2.x中其他的subscribe的重载方法返回Disposable

原始的Subscription容器类型已经被重命名和修改。

  • CompositeSubscription 改成 CompositeDisposable
  • SerialSubscription 和MultipleAssignmentSubscription 被合并到了 SerialDisposable。 set() 方法取消了旧值,而replace()方法没有。
  • RefCountSubscription 已被删除。

背压

Reactive-Streams规范的操作符支持背压,特别是当它们不发送请求时,它们不会溢出。新的操作符Flowable被设计成适合下游请求,然而这个不意味着MissingBackpressureException不会出现。这个异常仍然存在。但这一次,onNext会抛出这个异常。

作为替代,在2.x中Observable完全不支持背压,但可以被替换。

Reactive-Streams compliance

Flowable-based sources和operators是遵从Reactive-Streams 1.0.0规范的,除了一个规则§3.9和解释的规则§1.3:

§3.9: While the Subscription is not cancelled, Subscription.request(long n) MUST signal onError with a java.lang.IllegalArgumentException if the argument is <= 0. The cause message MUST include a reference to this rule and/or quote the full rule.

Rule §3.9 requires excessive overhead to handle (half-serializer on every operator dealing with request()) for a bug-case. RxJava 2 (and Reactor 3 in fact) reports the IllegalArgumentException to RxJavaPlugins.onError and ignores it otherwise. RxJava 2 passes the Test Compatibility Kit (TCK) by applying a custom operator that routes the IllegalArgumentException into the Subscriber.onError in an async-safe manner. All major Reactive-Streams libraries are free of such zero requests; Reactor 3 ignores it as we do and Akka-Stream uses a converter (to interact with other RS sources and consumers) which has (probably) a similar routing behavior as our TCK operator.

§1.3: onSubscribe, onNext, onError and onComplete signaled to a Subscriber MUST be signaled sequentially (no concurrent notifications).

TCK 允许同步但限制onSubscribe 和 onNext之间往返。也就是说在onSubscribe中,调用request(1)后将会调用onNext,在onNext返回后request(1)才会返回。虽然大部分操作符都是这样的,但操作符observeOn会异步的调用onNext,因此onSubscribe会和onNext同时被调用。这就是由TCK来检测,我们使用another operator来延迟下游请求直到onSubscribe返回。再次声明,这种异步行为不是RxJava 2的一个问题,因为在Reactor 3中操作符是线程安全的执行onSubscribe。Akka-Stream的转换类似于延迟请求。

因为这两个影响inter-library的行为,我们考虑在以后给Flowable增加了一个标准的操作符,把这两种行为改到一个单独的方法。

Runtime hooks

2.x 中重新设计了RxJavaPlugins类,现在支持运行时改变回调。测试需要重写schedulers,生命周期方法可以通过回调函数。

RxJavaObservableHook和友类现在都取消了,RxJavaHooks功能被加入到了RxJavaPlugins

Schedulers

在2.x的API中仍然支持主要的默认scheduler: computationionewThread 和 trampoline,可以通过io.reactivex.schedulers.Schedulers这个实用的工具类来调度。

2.x中不存在immediate 调度器。 它被频繁的误用,并没有正常的实现 Scheduler 规范;它包含用于延迟动作的阻塞睡眠,并且不支持递归调度。你可以使用Schedulers.trampoline()来代替它。

Schedulers.test()已经被移除,这样避免了默认调度器休息的概念差异。那些返回一个”global”的调度器实例是鉴于test()总是返回一个新的TestScheduler实例。现在我们鼓励测试人员使用这样简单的代码new TestScheduler()

io.reactivex.Scheduler抽象类现在支持直接调度任务,不需要先创建然后通过Worker调度。

public abstract class Scheduler {    public Disposable scheduleDirect(Runnable task) { ... }    public Disposable scheduleDirect(Runnable task, long delay, TimeUnit unit) { ... }    public Disposable scheduleDirectPeriodically(Runnable task, long initialDelay,         long period, TimeUnit unit) { ... }    public long now(TimeUnit unit) { ... }    // ... rest is the same: lifecycle methods, worker creation}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

主要的目的是为了避免跟踪Worker的开销。方法有一个默认的实现,你可以直接复用 createWorker ,但如果有需要,你也可以重写它来实现更强大的功能。

这些方法返回了当前时间调度器的概念, now()被改成接受一个用于指定单位量的TimeUnit的方法。

进入reactive的世界

RxJava 1.x的设计缺陷之一是暴露了rx.Observable.create()方法,该方法虽然很强大,但导致了你很少使用内置典型的操作符。不幸的是,有太多的代码依赖于这个库,所以我们不能删除或重命名它。

2.x是一个新的开始,我们不会再犯这个错误了。每一个基础类FlowableObservableSingleMaybe 和 Completable 都有安全的create操作符去支持背压和取消。

Flowable.create((FlowableEmitter<Integer> emitter) -> {    emitter.onNext(1);    emitter.onNext(2);    emitter.onComplete();}, BackpressureStrategy.BUFFER);
  • 1
  • 2
  • 3
  • 4
  • 5
  • 1
  • 2
  • 3
  • 4
  • 5

实际上,1.x中fromEmitter已经被重命名为Flowable.create。其他基础类型也有类似的create方法。

离开reactive的世界

除了subscribing 各自的consumers(SubscriberObserverSingleObserverMaybeObserver 和 CompletableObserver) 以及functional-interface 基础consumers(例如

subscribe(Consumer<T>, Consumer<Throwable>, Action)),以前在1.x中独立的BlockingObservable 已经集成了主要的基础类型。现在你可以直接调用blockingX来阻塞等待结果:

List<Integer> list = Flowable.range(1, 100).toList().blockingGet(); // toList() returns SingleInteger i = Flowable.range(100, 100).blockingLast();
  • 1
  • 2
  • 3
  • 1
  • 2
  • 3

在2.x中另外一个关于rx.Subscriber 和org.reactivestreams.Subscriber重要的区别是,你的SubscriberObserver不允许抛出任何致命的异常。这意味着下面这样的代码不再是合法的:

Subscriber<Integer> subscriber = new Subscriber<Integer>() {    @Override    public void onSubscribe(Subscription s) {        s.request(Long.MAX_VALUE);    }    public void onNext(Integer t) {        if (t == 1) {            throw new IllegalArgumentException();        }    }    public void onError(Throwable e) {        if (e instanceof IllegalArgumentException) {            throw new UnsupportedOperationException();        }    }    public void onComplete() {        throw new NoSuchElementException();    }};Flowable.just(1).subscribe(subscriber);
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24

这样的规则同样适用于ObserverSingleObserverMaybeObserver 和 CompletableObserver

由于很多现有基于1.x的代码做了类似的事情,我们设计了safeSubscribe方法来帮助你处理这样的代码。

当然你也可以使用

subscribe(Consumer<T>, Consumer<Throwable>, Action)方法来提供一个回调。

Flowable.just(1).subscribe(    subscriber::onNext,     subscriber::onError,     subscriber::onComplete,     subscriber::onSubscribe);
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

Testing

测试RxJava 2.x和1.x中一样,Flowable可以用io.reactivex.subscribers.TestSubscriber测试,而非背压的ObservableSingleMaybe 和 Completable可以用io.reactivex.observers.TestObserver测试。

test() “operator”

为了支持我们内部测试,所有的基础类都有 test() 方法,返回TestSubscriber 或 TestObserver:

TestSubscriber<Integer> ts = Flowable.range(1, 5).test();TestObserver<Integer> to = Observable.range(1, 5).test();TestObserver<Integer> tso = Single.just(1).test();TestObserver<Integer> tmo = Maybe.just(1).test();TestObserver<Integer> tco = Completable.complete().test();
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

第二个便利之处在于,大部分TestSubscriber/TestObserver方法返回自身实例,这让我们可以链式调用各种assertX方法。第三个便利是,你可以流畅的测试你的代码而不需要去创建或者引入TestSubscriber/TestObserver实例。

Flowable.range(1, 5).test().assertResult(1, 2, 3, 4, 5);
  • 1
  • 2
  • 3
  • 4
  • 1
  • 2
  • 3
  • 4

值得注意的新的断言方法

  • assertResult(T... items): 断言在onComplete中将会按指定顺序收到给定的值,并且没有错误。
  • assertFailure(Class<? extends Throwable> clazz, T... items): 断言将会收到指定的异常。
  • assertFailureAndMessage(Class<? extends Throwable> clazz, String message, T... items): 和assertFailure一样,但还会验证 getMessage() 中包含的值。
  • awaitDone(long time, TimeUnit unit) 等待一个终结事件,如果超时了,将会取消该事件。
  • assertOf(Consumer<TestSubscriber<T>> consumer) 组成一些断言到流式链中。

其中一个好处是,把Flowable改为Observable,所以测试代码不需要改变,内部的已经把TestSubscriber改成了TestObserver

提前取消和请求

TestObserver中的test()方法有一个 test(boolean cancel) 重载,它能在订阅前取消TestSubscriber/TestObserver:

PublishSubject<Integer> pp = PublishSubject.create();// nobody subscribed yetassertFalse(pp.hasSubscribers());pp.test(true);// nobody remained subscribedassertFalse(pp.hasSubscribers());
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

TestSubscriber 有 test(long initialRequest) 和 test(long initialRequest, boolean cancel) 重载,用于指定初始请求数量以及TestSubscriber是否应该立即被取消。如果initialRequest被给定,TestSubscriber 实例通常需要被捕获以便访问request()方法:

PublishProcessor<Integer> pp = PublishProcessor.create();TestSubscriber<Integer> ts = pp.test(0L);ts.request(1);pp.onNext(1);pp.onNext(2);ts.assertFailure(MissingBackpressureException.class, 1);
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

测试异步代码

对于给定的异步代码,流畅的阻塞终端事件是可能的:

Flowable.just(1).subscribeOn(Schedulers.single()).test().awaitDone(5, TimeUnit.SECONDS).assertResult(1);
  • 1
  • 2
  • 3
  • 4
  • 5
  • 1
  • 2
  • 3
  • 4
  • 5

Mockito & TestSubscriber

那些在1.x中正在使用Mockito和Observer的用户需要去使用Subscriber.onSubscribe方法去提出初始的请求,否则序列化将会挂起或者失败:

@SuppressWarnings("unchecked")public static <T> Subscriber<T> mockSubscriber() {    Subscriber<T> w = mock(Subscriber.class);    Mockito.doAnswer(new Answer<Object>() {        @Override        public Object answer(InvocationOnMock a) throws Throwable {            Subscription s = a.getArgumentAt(0, Subscription.class);            s.request(Long.MAX_VALUE);            return null;        }    }).when(w).onSubscribe((Subscription)any());    return w;}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15

操作符的差别

2.x中大部分操作符仍然被保留,实际上大部分行为和1.x一样。下面的列表中列出了每一个基础类的在1.x和2.x的区别

通常来说,很多操作符提供了重载,允许指定运行上游的内部缓冲区的大小或者预先分配的数量。

一些操作符重载已经被重命名为了后缀风格,比如 fromArrayfromIterable。这么做的原因是,当用Java 8编译时,javac往往不能区分功能接口类型。

在1.x中被标记为@Beta 或 @Experimental的操作符已经成为正式操作符了。

1.x Observable 到 2.x Flowable

工厂方法:

1.x2.xamb添加 amb(ObservableSource...) 重载, 2-9 参数被删除RxRingBuffer.SIZEbufferSize()combineLatest增加条目重载, 增加 带bufferSize 参数的重载, combineLatest(List) 被删除concat增加带 prefetch 参数的重载, 5-9 重载被删除 , 使用 concatArray 代替N/A增加 concatArray 和 concatArrayDelayErrorN/A增加 concatArrayEager 和 concatArrayEagerDelayErrorconcatDelayError增加带延时的重载concatEagerDelayError增加带延时的重载create(SyncOnSubscribe)被 generate + 重载代替create(AsnycOnSubscribe)不存在create(OnSubscribe)使用安全的 create(FlowableOnSubscribe, BackpressureStrategy), 支持 unsafeCreate()from拆分成 fromArrayfromIterablefromFutureN/A增加 fromPublisherfromAsync重命名为 create()N/A增加 intervalRange()limit被删除, 使用 takemerge增加带 prefetch的重载mergeDelayError增加带 prefetch的重载sequenceEqual增加带 bufferSize的重载switchOnNext增加带 prefetch的重载switchOnNextDelayError增加带 prefetch的重载timer被废弃zip增加带 bufferSize 和 delayErrors 的重载, 拆分成了 zipArray 和 zipIterable

实例方法:

1.x2.xallRC3 返回 Single<Boolean>anyRC3 返回 Single<Boolean>asObservable重命名为 hide(), 隐藏所有的身份buffer重载自定义的 Collection 提供者cache(int)被废弃collectRC3 返回 Single<U>collect(U, Action2<U, T>)改成 collectInto 和 RC3 返回 Single<U>concatMap增加带 prefetch 的重载concatMapDelayError增加带 prefetch的重载, 支持延时concatMapEager增加带 prefetch的重载concatMapEagerDelayError增加带 prefetch的重载, 支持延时countRC3 返回 Single<Long>countLong被删除, 使用 countdistinct重载自定义的 Collection 提供者.doOnCompleted重命名为 doOnCompletedoOnUnsubscribe重命名为 Flowable.doOnCancel 和 doOnDispose , additional infoN/A增加 doOnLifecylce 来处理 onSubscriberequest 和 cancelelementAt(int)RC3 不再发射 NoSuchElementException 如果源比索引更小elementAt(Func1, int)被删除, 使用 filter(predicate).elementAt(int) 代替elementAtOrDefault(int, T)重命名为 elementAt(int, T) 和 RC3 返回 Single<T>elementAtOrDefault(Func1, int, T)被删除, 使用 filter(predicate).elementAt(int, T) 代替first()RC3 重命名为 firstElement 返回 Maybe<T>first(Func1)被删除, 使用 filter(predicate).first()代替firstOrDefault(T)重命名为 first(T) RC3 返回 Single<T>firstOrDefault(Func1, T)被删除, 使用 filter(predicate).first(T)代替flatMap增加带 prefetch的重载N/A增加
forEachWhile(Predicate<T>, [Consumer<Throwable>, [Action]]) 用于有条件停止 consumptiongroupBy增加带 bufferSize和 delayError的重载, 支持 支持内部自定义map,RC1中没有ignoreElementsRC3 返回 CompletableisEmptyRC3 返回 Single<Boolean>last()RC3 重命名为 lastElement 返回 Maybe<T>last(Func1)被删除, 使用 filter(predicate).last()代替lastOrDefault(T)重命名为 last(T) RC3 返回 Single<T>lastOrDefault(Func1, T)被删除, 使用 filter(predicate).last(T)代替nest被删除, 使用 just代替publish(Func1)增加带 prefetch的重载reduce(Func2)RC3 返回 Maybe<T>N/A增加 reduceWith(Callable, BiFunction) 为了减少自定义Subscriber, 返回 Single<T>N/A增加 repeatUntil(BooleanSupplier)repeatWhen(Func1, Scheduler)删除了重载, 使用 subscribeOn(Scheduler).repeatWhen(Function) 代替retry增加 retry(Predicate)retry(int, Predicate)N/A增加 retryUntil(BooleanSupplier)retryWhen(Func1, Scheduler)删除了重载, 使用 subscribeOn(Scheduler).retryWhen(Function) 代替N/A增加 sampleWith(Callable, BiFunction) 去扫描自定义的Subscriber方式single()RC3 重命名为 singleElement 返回 Maybe<T>single(Func1)被删除,使用 filter(predicate).single()代替singleOrDefault(T)重命名为 single(T) RC3 返回 Single<T>singleOrDefault(Func1, T)被删除,使用 filter(predicate).single(T)代替skipLast增加带 bufferSize 和 delayError 的重载startWith2-9 参数的被删除了, 使用 startWithArray 代替N/A增加 startWithArray 来减少二义性N/A增加 subscribeWith 返回输入的订阅对象switchMap增加带 prefetch 的重载switchMapDelayError增加带 prefetch 的重载takeLastBuffer被删除N/A增加 test()timeout(Func0<Observable>, ...)方法签名改成了 timeout(Publisher, ...) 删除了方法, 如果有需要,使用 defer(Callable<Publisher>>)toBlocking().y内联 blockingY() 操作符, 除了 toFuturetoCompletableRC3 被删除, 使用 ignoreElements代替toListRC3 返回 Single<List<T>>toMapRC3 返回 Single<Map<K, V>>toMultimapRC3 返回 Single<Map<K, Collection<V>>>N/A增加 toFutureN/A增加 toObservabletoSingleRC3 被删除, 使用 single(T)代替toSortedListRC3 增加 Single<List<T>>withLatestFrom5-9 个参数的重载被删除zipWith增加带 prefetch 和 delayErrors 的重载

不同的返回类型

2.x中一些的操作符产生确切的一个值或者一个错误时,返回Single

操作符旧返回值新返回值备注all(Predicate)Observable<Boolean>Single<Boolean>如果所有的元素都匹配,则发射trueany(Predicate)Observable<Boolean>Single<Boolean>如果所有的元素都匹配,则发射truecount()Observable<Long>Single<Long>计算序列中元素的数量elementAt(int)Observable<T>Maybe<T>Emits 给定位置处的元素或完成的元素elementAt(int, T)Observable<T>Single<T>发射指定位置的元素或默认元素first(T)Observable<T>Single<T>发射第一个元素或者抛出 NoSuchElementExceptionfirstElement()Observable<T>Maybe<T>发射第一个元素或者结束ignoreElements()Observable<T>Completable忽略所有非终端事件isEmpty()Observable<Boolean>Single<Boolean>如果源为空,则发射truelast(T)Observable<T>Single<T>发射最后一个元素或默认值lastElement()Observable<T>Maybe<T>发射最后一个元素或结束reduce(BiFunction)Observable<T>Maybe<T>发射减少的值或者结束reduce(Callable, BiFunction)Observable<U>Single<U>发射减少的值或者初始的值reduceWith(U, BiFunction)Observable<U>Single<U>发射减少的值或者初始的值single(T)Observable<T>Single<T>发射唯一的元素或默认值singleElement()Observable<T>Maybe<T>发射唯一的元素或结束toList()Observable<List<T>>Single<List<T>>将所有元素放到 ListtoMap()Observable<Map<K, V>>Single<Map<K, V>>将所有元素放到 MaptoMultimap()Observable<Map<K, Collection<V>>>Single<Map<K, Collection<V>>>将所有元素包装到Collection后放到 MaptoSortedList()Observable<List<T>>Single<List<T>>将所有元素放到 List 并排序

移除

为了保证最终的2.0API尽可能干净,我们删除了一些候选的方法和组件。

删除时的版本组件备注RC3Flowable.toCompletable()使用 Flowable.ignoreElements()代替RC3Flowable.toSingle()使用 Flowable.single(T)代替RC3Flowable.toMaybe()使用 Flowable.singleElement()代替RC3Observable.toCompletable()使用 Observable.ignoreElements()代替RC3Observable.toSingle()使用 Observable.single(T)代替RC3Observable.toMaybe()使用 Observable.singleElement()代替

其他改变

doOnCancel/doOnDispose/unsubscribeOn

在1.x中,doOnUnsubscribe总是执行终端事件,因为SafeSubscriber调用了unsubscribe。这实际上是没有必要的。Reactive-Streams规范中,一个终端事件到达Subscriber,上游的Subscription会取消,因此调用 cancel()是一个空操作。

由于同样的原因unsubscribeOn也没被在终端路径上调用,但只有实际在链上调用cancel时,才会调用unsubscribeOn

因此,下面的序列不会被调用 
doOnCancel:

Flowable.just(1, 2, 3).doOnCancel(() -> System.out.println("Cancelled!")).subscribe(System.out::println);
  • 1
  • 2
  • 3
  • 1
  • 2
  • 3

然而,下面将会调用take操作符在传送过程中取消onNext

Flowable.just(1, 2, 3).doOnCancel(() -> System.out.println("Cancelled!")).take(2).subscribe(System.out::println);
  • 1
  • 2
  • 3
  • 4
  • 1
  • 2
  • 3
  • 4

如果你需要在终端或者取消时执行清理,考虑使用using操作符代替。

转自:http://blog.csdn.net/qq_35064774/article/details/53045298

原创粉丝点击