原文:RxJava
###RxJava: Reactive Extensions for the JVM
###RxJava:JVM的反应扩展
RxJava is a java VM implementation of Reactive Extensions: a library for composing asynchronous and event-based programs by using observable sequences.
RxJava 是一个 JVM 关于反应拓展的实现,一个通过可观察序列实现异步和事件项目的库
It extends the ovserver pattern to support sequences of data/events and adds operators that allow you to compose sequences together declaratively while abstracting away concerns about things like low-level threading ,synchronization,thread-safety and concurrent data structures.
它扩展了观察者模式来支持数据/事件的序列,并添加了允许您以声明的方式组合序列的操作符,同时抽象出对诸如低级线程、同步、线程安全和并发数据结构等方面的关注。
- single dependency: Reactive-Streams
- continued support for Java 6+ & Android 2.3+
- Java 8 lambda-friendly API
- non-opinionated about source of concurrency (threads, pools, event loops, fibers, actors, etc)
- async or synchronous execution
- virtual time and schedulers for parameterized concurrency
单一依赖: 反应流
继续支持 Java 6+ & Android 2.3+
Java 8 lambda-友好 API
对并发源(线程、池、事件循环、纤维、参与者等)兼容。
异步或同步执行
用于参数化并发的虚拟时间和调度程序
Version 2.x and 1.x will live side-by-side for several years. They will have different group ids (io.reactivex.rxjava2 vs io.reactivex) and namespaces (io.reactivex vs rx).
版本2。x和1。x将在一起存在数年。它们会有不同的组id(io.reactivex。rxjava2 vs.reactivex)和名称空间(io。reactivex vs rx)。
See the differences between version 1.x and 2.x in the wiki article What’s different in 2.0. Learn more about RxJava in general on the Wiki Home.
参见版本1之间的区别。x和2。在维基文章中,x在2。0中有什么不同。在维基的主页上了解更多关于RxJava的信息。
###Getting started
###开始使用
Setting up the dependency
设置依赖
The first step is to include RxJava 2 into your project, for example, as a Gradle compile dependency:
第一步是将RxJava 2 引入到你的项目,例如,Gradle方式添加compile依赖
compile “io.reactivex.rxjava2:rxjava:2.x.y”
(Please replace x and y with the latest version numbers:
请将x和y用最新的版本号代替
Hello World
简单使用
The second is to write the Hello World program:
第二步是写一个简单的程序
package rxjava.examples;
import io.reactivex.*;
public class HelloWorld {
public static void main(String[] args) {
Flowable.just("Hello world").subscribe(System.out::println);
}
}
If your platform doesn’t support Java 8 lambdas (yet), you have to create an inner class of Consumer manually:
如果你的平台还不支持 java8 8 lambdas,你需要手动创建一个内部类 Consumer(消费者)
import io.reactivex.functions.Consumer;
Flowable.just("Hello world")
.subscribe(new Consumer<String>() {
@Override public void accept(String s) {
System.out.println(s);
}
});
Base classes
RxJava 2 features several base classes you can discover operators on:
RxJava 2 有几个基本的类你可以在上面发现操作符
io.reactivex.Flowable: 0…N flows, supporting Reactive-Streams and backpressure
Flowable可流动的,0…N流,支持活动流和反压力
io.reactivex.Observable: 0…N flows, no backpressure,
可观测的,0…N流,无反压力
io.reactivex.Single: a flow of exactly 1 item or an error,
一个恰好是1个或一个错误的流,
io.reactivex.Completable: a flow without items but only a completion or error signal,
Completable 可完备的,一个没有项目的流程,但只有一个完成或错误信号
io.reactivex.Maybe: a flow with no items, exactly one item or an error.
一个没有项目的流程,一个项目或一个错误。
Some terminology
一些术语
Upstream, downstream
上游、下游
The dataflows in RxJava consist of a source, zero or more intermediate steps followed by a data consumer or combinator step (where the step is responsible to consume the dataflow by some means):
RxJava中的数据流由一个源、零个或多个中间步骤组成,然后是一个数据使用者或组合子步骤(其中的步骤是通过某种方式来消耗数据流):
source.operator1().operator2().operator3().subscribe(consumer);
source.flatMap(value -> source.operator1().operator2().operator3());
Here, if we imagine ourselves on operator2, looking to the left towards the source, is called the upstream. Looking to the right towards the subscriber/consumer, is called the downstream. This is often more apparent when each element is written on a separate line:
这里,如果我们想象自己在operator2上,向左看向源,被称为上游。面向订户/消费者的权利,称为下游。当每个元素都写在单独的一行上时,这通常更明显:
source
.operator1()
.operator2()
.operator3()
.subscribe(consumer)
Objects in motion
运动的物体
In RxJava’s documentation, emission, emits, item, event, signal, data and message are considered synonyms and represent the object traveling along the dataflow.
在RxJava的文档中,发射、发出、项目、事件、信号、数据和消息被视为同义词,并表示沿着数据流运行的对象。
When the dataflow runs through asynchronous steps, each step may perform different things with different speed. To avoid overwhelming such steps, which usually would manifest itself as increased memory usage due to temporary buffering or the need for skipping/dropping data, a so-called backpressure is applied, which is a form of flow control where the steps can express how many items are they ready to process. This allows constraining the memory usage of the dataflows in situations where there is generally no way for a step to know how many items the upstream will send to it.
当dataflow通过异步步骤运行时,每个步骤可以以不同的速度执行不同的操作。为了避免这样的步骤,通常会表现为由于临时缓冲或需要跳过/删除数据而增加内存使用量,所以应用了所谓的“反压力”,这是一种流控制的形式,在这种情况下,步骤可以表示他们准备处理的项目有多少。这允许在通常无法知道上游将发送多少项的情况下,限制数据流的内存使用。
In RxJava, the dedicated Flowable class is designated to support backpressure and Observable is dedicated for the non-backpressured operations (short sequences, GUI interactions, etc.).The other types, Single, Maybe and Completable don’t support backpressure nor should they; there is always room to store one item temporarily.
在RxJava中,专用的流式类被指定为支持反压力和可观察的,用于非回压操作(短序列、GUI交互等)。另一种类型,单个的,可能和完全的不支持反压力,也不应该支持。总有一个地方可以暂时存放一件物品。
Assembly time
装配时间
The preparation of dataflows by applying various intermediate operators happens in the so-called assembly time:
在所谓的装配时间内,应用不同的中间操作符来准备dataflow:
Flowable<Integer> flow = Flowable.range(1, 5)
.map(v -> v* v)
.filter(v -> v % 3 == 0);
At this point, the data is not flowing yet and no side-effects are happening.
此时,数据还没有流动,也没有任何副作用。
Subscription time
订购时间
This is a temporary state when subscribe() is called on a flow that establishes the chain of processing steps internally:
这是subscribe()时的临时状态,该流在内部建立处理步骤链:
flow.subscribe(System.out::println)
This is when the subscription side-effects are triggered (see doOnSubscribe). Some sources block or start emitting items right away in this state.
这时会触发订阅副作用(参见doOnSubscribe)。一些源在这个状态下阻塞或开始释放项目。
Runtime
This is the state when the flows are actively emitting items, errors or completion signals:
这是当流主动发出项目、错误或完成信号时的状态:
Observable.create(emitter -> {
while (!emitter.isDisposed()) {
long time = System.currentTimeMillis();
emitter.onNext(time);
if (time % 2 != 0) {
emitter.onError(new IllegalStateException("Odd millisecond!"));
break;
}
}
})
.subscribe(System.out::println, Throwable::printStackTrace);
Practically, this is when the body of the given example above executes.
实际上,这是当上面的给定示例的主体执行时。
Simple background computation
简单的背景计算
One of the common use cases for RxJava is to run some computation, network request on a background thread and show the results (or error) on the UI thread:
RxJava的一个常见用例是在后台线程上运行一些计算、网络请求,并在UI线程上显示结果(或错误):
import io.reactivex.schedulers.Schedulers;
Flowable.fromCallable(() -> {
Thread.sleep(1000); // imitate expensive computation
return "Done";
})
.subscribeOn(Schedulers.io())
.observeOn(Schedulers.single())
.subscribe(System.out::println, Throwable::printStackTrace);
Thread.sleep(2000); // <--- wait for the flow to finish
This style of chaining methods is called a fluent API which resembles the builder pattern.
这种类型的链接方法称为流畅的 API,类似于构建器模式。
However, RxJava’s reactive types are immutable; each of the method calls returns a new Flowable with added behavior. To illustrate, the example can be rewritten as follows:
然而,RxJava的反应类型是不可变的;每一个方法调用都返回一个新的可流的附加行为。为了说明,这个例子可以改写如下:
Flowable<String> source = Flowable.fromCallable(() -> {
Thread.sleep(1000); // imitate expensive computation
return "Done";
});
Flowable<String> runBackground = source.subscribeOn(Schedulers.io());
Flowable<String> showForeground = runBackground.observeOn(Schedulers.single());
showForeground.subscribe(System.out::println, Throwable::printStackTrace);
Thread.sleep(2000);
Typically, you can move computations or blocking IO to some other thread via subscribeOn.
通常,您可以通过subscribeOn移动计算或阻塞IO到其他线程。
Once the data is ready, you can make sure they get processed on the foreground or GUI thread via observeOn.
一旦数据准备好,您就可以确保它们通过observeOn在前台或GUI线程上处理。
Schedulers
调度器
RxJava operators don’t work with Threads or ExecutorServices directly but with so called Schedulers that abstract away sources of concurrency behind an uniform API.
RxJava操作符不直接使用线程或ExecutorServices,而是使用所谓的调度程序来抽象出统一API背后的并发源。
RxJava 2 features several standard schedulers accessible via Schedulers utility class.
RxJava 2有几个标准调度器,可通过调度器工具类访问。
Schedulers.computation(): Run computation intensive work on a fixed number of dedicated threads in the background. Most asynchronous operator use this as their default Scheduler.
Schedulers.computation():在后台的固定数量的专用线程上运行计算密集型工作。大多数异步操作符使用这个作为默认的调度器。
Schedulers.io(): Run I/O-like or blocking operations on a dynamically changing set of threads.
io():在动态变化的线程集合上运行I/ o like或阻塞操作。
Schedulers.single(): Run work on a single thread in a sequential and FIFO manner.
single():以顺序和FIFO方式在单个线程上运行工作。
Schedulers.trampoline(): Run work in a sequential and FIFO manner in one of the participating threads, usually for testing purposes.
Schedulers.trampoline(): 在一个参与线程中以顺序和FIFO方式运行工作,通常用于测试目的。
These are available on all JVM platforms but some specific platforms, such as Android, have their own typical Schedulers
这些在所有的JVM平台上都可以使用,但是一些特定的平台,比如Android,有他们自己的典型调度器。
defined: AndroidSchedulers.mainThread(), SwingScheduler.instance() or JavaFXSchedulers.gui().
定义:android调度程序。mainthread()、swingschedule .instance()或javafxschedule .gui()。
In addition, there is option to wrap an existing Executor (and its subtypes such as ExecutorService) into a Scheduler via Schedulers.from(Executor).
此外,还可以通过调度程序将现有的Executor(及其子类型,如ExecutorService)包装到调度程序中。
This can be used, for example, to have a larger but still fixed pool of threads (unlike computation() and io() respectively).
例如,可以使用这个方法,将一个较大但仍然固定的线程池(不像计算()和io())。
The Thread.sleep(2000); at the end is no accident. In RxJava the default Schedulers run on daemon threads, which means once the Java main thread exits, they all get stopped and background computations may never happen. Sleeping for some time in this example situations lets you see the output of the flow on the console with time to spare.
thread . sleep(2000);
最后并非偶然。在RxJava中,默认的调度程序运行在守护线程上,这意味着一旦Java主线程退出,它们都会停止,而后台计算可能永远不会发生。在这个示例场景中,休眠一段时间可以让您看到控制台中的流输出,从而节省时间。
Concurrency within a flow
在流的并发性
Flows in RxJava are sequential in nature split into processing stages that may run concurrently with each other:
RxJava中的流是连续的,在本质上分为处理阶段,可以并发地运行:
Flowable.range(1, 10)
.observeOn(Schedulers.computation())
.map(v -> v * v)
.blockingSubscribe(System.out::println);
This example flow squares the numbers from 1 to 10 on the computation Scheduler and consumes the results on the “main” thread (more precisely, the caller thread of blockingSubscribe). However, the lambda v -> v * v doesn’t run in parallel for this flow; it receives the values 1 to 10 on the same computation thread one after the other.
这个示例流在计算调度器上的数字从1到10,并在“main”线程(更准确地说,是blockingSubscribe的调用线程)上使用结果。然而,v -> v * v并不能与此流并行运行;在相同的计算线程中,它接收的值是1到10。
Parallel processing
并发处理
Processing the numbers 1 to 10 in parallel is a bit more involved:
并行处理1到10的数字有点复杂:
Flowable.range(1, 10)
.flatMap(v ->
Flowable.just(v)
.subscribeOn(Schedulers.computation())
.map(w -> w * w)
)
.blockingSubscribe(System.out::println);
Practically, parallelism in RxJava means running independent flows and merging their results back into a single flow. The operator flatMap does this by first mapping each number from 1 to 10 into its own individual Flowable, runs them and merges the computed squares.
实际上,RxJava中的并行性意味着运行独立的流并将其结果合并回单个流中。操作员flatMap通过将每个数字从1到10映射到它自己的流中,运行它们并合并计算的平方。
Note, however, that flatMap doesn’t guarantee any order and the end result from the inner flows may end up interleaved. There are alternative operators:
但是,请注意,flatMap并不能保证任何顺序,内部流的最终结果可能会交叉。有选择运营商:
concatMap that maps and runs one inner flow at a time and
concatMap映射和运行一次内部流。
concatMapEager which runs all inner flows “at once” but the output flow will be in the order those inner flows were created.
concatMapEager可以“立即”运行所有的内部流,但是输出流将按照创建内部流的顺序进行。
Alternatively, there is a beta operator Flowable.parallel() and type ParallelFlowable that helps achieve the same parallel processing pattern:
此外,还有一个beta操作符flow .parallel()和type ParallelFlowable可以帮助实现相同的并行处理模式:
Flowable.range(1, 10)
.parallel()
.runOn(Schedulers.computation())
.map(v -> v * v)
.sequential()
.blockingSubscribe(System.out::println);
Dependent sub-flows
依赖基流
flatMap is a powerful operator and helps in a lot of situations. For example, given a service that returns a Flowable, we’d like to call another service with values emitted by the first service:
flatMap是一个强大的操作符,在很多情况下都有帮助。例如,给定一个返回可流的服务,我们希望调用另一个服务,它的值由第一项服务发出:
Flowable inventorySource = warehouse.getInventoryAsync();
inventorySource.flatMap(inventoryItem ->
erp.getDemandAsync(inventoryItem.getId())
.map(demand
-> System.out.println("Item " + inventoryItem.getName() + " has demand " + demand));
)
.subscribe();
Continuations
附录
Sometimes, when an item has become available, one would like to perform some dependent computations on it. This is sometimes called continuations and, depending on what should happen and what types are involved, may involve various operators to accomplish.
有时,当一个项目变得可用时,一个人想要对它执行一些依赖的计算。他有时被称为延续,根据所要发生的事情以及所涉及的类型,可能需要不同的操作人员来完成。
Dependent
依靠的
The most typical scenario is to given a value, invoke another service, await and continue with its result:
最典型的场景是给定一个值,调用另一个服务,等待并继续其结果:
service.apiCall()
.flatMap(value -> service.anotherApiCall(value))
.flatMap(next -> service.finalCall(next))
It is often the case also that later sequences would require values from earlier mappings. This can be achieved by moving the outer flatMap into the inner parts of the previous flatMap for example:
通常情况下,后面的序列需要从早期的映射中得到值。这可以通过将外部平面图移动到上一个平面地图的内部部分来实现,例如:
service.apiCall()
.flatMap(value ->
service.anotherApiCall(value)
.flatMap(next -> service.finalCallBoth(value, next))
)
Here, the original value will be available inside the inner flatMap, courtesy of lambda variable capture.
这里,原始值将在内部平面地图中可用,由lambda变量捕获提供。
Non-dependent
非依赖性
In other scenarios, the result(s) of the first source/dataflow is irrelevant and one would like to continue with a quasi independent another source. Here, flatMap works as well:
在其他情况下,第一个源/数据流的结果是不相关的,并且希望继续使用准独立的另一个源。在这里,平面地图同样适用:
Observable continued = sourceObservable.flatMapSingle(ignored -> someSingleSource)
continued.map(v -> v.toString())
.subscribe(System.out::println, Throwable::printStackTrace);
however, the continuation in this case stays Observable instead of the likely more appropriate Single. (This is understandable because from the perspective of flatMapSingle, sourceObservable is a multi-valued source and thus the mapping may result in multiple values as well).
然而,这种情况下的延续是可观察的,而不是可能更合适的单一。(这是可以理解的,因为从flatMapSingle的角度来看,sourceObservable是一个多值的源,因此映射可能会导致多个值)。
Often though there is a way that is somewhat more expressive (and also lower overhead) by using Completable as the mediator and its operator andThen to resume with something else:
通常情况下,通过使用Completable作为中介和它的操作符,然后使用其他的东西来恢复,通常会有一种更富表现力(同时也更低的开销)的方式:
sourceObservable
.ignoreElements() // returns Completable
.andThen(someSingleSource)
.map(v -> v.toString())
The only dependency between the sourceObservable and the someSingleSource is that the former should complete normally in order for the latter to be consumed.
sourceObservable和someSingleSource之间唯一的依赖关系是前者应该正常地完成,以使后者被消费。
Deferred-dependent
延缓的依赖
Sometimes, there is an implicit data dependency between the previous sequence and the new sequence that, for some reason, was not flowing through the “regular channels”. One would be inclined to write such continuations as follows:
有时,在前一个序列和新序列之间存在一个隐式的数据依赖关系,出于某种原因,它并不是通过“常规通道”流动的.一个人倾向于写这样的延续如下:
AtomicInteger count = new AtomicInteger();
Observable.range(1, 10)
.doOnNext(ignored -> count.incrementAndGet())
.ignoreElements()
.andThen(Single.just(count.get()))
.subscribe(System.out::println);
Unfortunately, this prints 0 because Single.just(count.get()) is evaluated at assembly time when the dataflow hasn’t even run yet. We need something that defers the evaluation of this Single source until runtime when the main source completes:
不幸的是,这个打印输出为0,因为单个。just(count.get())是在数据流还没有运行时在组装时计算的。我们需要一些东西,在主源完成时,将对该单个源的评估延迟到运行时:
AtomicInteger count = new AtomicInteger();
Observable.range(1, 10)
.doOnNext(ignored -> count.incrementAndGet())
.ignoreElements()
.andThen(Single.defer(() -> Single.just(count.get())))
.subscribe(System.out::println);
or
AtomicInteger count = new AtomicInteger();
Observable.range(1, 10)
.doOnNext(ignored -> count.incrementAndGet())
.ignoreElements()
.andThen(Single.fromCallable(() -> count.get()))
.subscribe(System.out::println);
Type conversions
类型转换
Sometimes, a source or service returns a different type than the flow that is supposed to work with it. For example, in the inventory example above, getDemandAsync could return a Single. If the code example is left unchanged, this will result in a compile time error (however, often with misleading error message about lack of overload).
有时候,源或服务返回的类型与应该使用它的流不同。例如,在上面的清单示例中,getDemandAsync可以返回一个单独的。如果代码示例没有发生变化,这将导致编译时错误(不过,通常会出现错误信息,说明缺少过载)。
Sometimes, a source or service returns a different type than the flow that is supposed to work with it. For example, in the inventory example above, getDemandAsync could return a Single. If the code example is left unchanged, this will result in a compile time error (however, often with misleading error message about lack of overload).
In such situations, there are usually two options to fix the transformation: 1) convert to the desired type or 2) find and use an overload of the specific operator supporting the different type.
有时候,源或服务返回的类型与应该使用它的流不同。例如,在上面的清单示例中,getDemandAsync可以返回一个单独的。如果代码示例没有发生变化,这将导致编译时错误(不过,通常会出现错误信息,说明缺少过载)。在这种情况下,通常有两个选项来修复转换:1)转换为所需的类型或2)查找并使用支持不同类型的特定操作符重载。
Converting to the desired type
转换为所需类型
Each reactive base class features operators that can perform such conversions, including the protocol conversions, to match some other type.The following matrix shows the available conversion options:
每个反应基类都具有可以执行此类转换的操作符,包括协议转换,以匹配其他类型。以下矩阵显示可用的转换选项:
Flowable Observable Single Maybe Completable
Flowable toObservable first, firstOrError, single, singleOrError, last, lastOrError1 firstElement, singleElement, lastElement ignoreElements
Observable toFlowable2 first, firstOrError, single, singleOrError, last, lastOrError1 firstElement, singleElement, lastElement ignoreElements
Single toFlowable3 toObservable toMaybe toCompletable
Maybe toFlowable3 toObservable toSingle ignoreElement
Completable toFlowable toObservable toSingle toMaybe
1: When turning a multi-valued source into a single valued source, one should decide which of the many source values should be considered as the result.
当将多值源转换为单个值源时,应该决定哪些源值应该被考虑为结果。
2: Turning an Observable into Flowable requires an additional decision: what to do with the potential unconstrained flow of the source Observable?
2:将可观察的事物转化为可流动的需要一个额外的决定:如何处理源可观察到的不受约束的流?有几种可用的策略(如缓冲、删除、保留最新的)通过BackpressureStrategy参数或通过标准的可流操作符,如onBackpressureBuffer、onBackpressureDrop、onbackpressure - est,这也允许进一步定制反压力行为。
3: When there is only (at most) one source item, there is no problem with backpressure as it can be always stored until the downstream is ready to consume.
3:当只有一个源项(最多)时,反压力没有问题,因为它可以一直存储到下游准备消费。
Using an overload with the desired type
使用期望类型的重载。
Many frequently used operator has overloads that can deal with the other types. These are usually named with the suffix of the target type:
许多经常使用的操作符重载,可以处理其他类型。这些通常以目标类型的后缀命名:
Operator Overloads
flatMap flatMapSingle, flatMapMaybe, flatMapCompletable, flatMapIterable
concatMap concatMapSingle, concatMapMaybe, concatMapCompletable, concatMapIterable
switchMap switchMapSingle, switchMapMaybe, switchMapCompletable
The reason these operators have a suffix instead of simply having the same name with different signature is type erasure. Java doesn’t consider signatures such as operator(Function<T, Single>) and operator(Function<T, Maybe>) different (unlike C#) and due to erasure, the two operators would end up as duplicate methods with the same signature.
这些操作符有一个后缀而不是简单地具有不同签名的名称的原因是类型消除。Java不考虑诸如运算符(函数<T, Single>)和运算符(函数<T,可能>)不同(不像c#)的签名,并且由于擦除,两个操作符会以相同的签名作为重复的方法。
Operator naming conventions
运营商的命名约定
Naming in programming is one of the hardest things as names are expected to be not long, expressive, capturing and easily memorable. Unfortunately, the target language (and pre-existing conventions) may not give too much help in this regard (unusable keywords, type erasure, type ambiguities, etc.).
在编程中命名是最困难的事情之一,因为名字预计不会很长,很有表现力,很容易被记住。不幸的是,目标语言(以及预先存在的约定)在这方面可能不会提供太多的帮助(不可用的关键字、类型擦除、类型歧义等)。
Unusable keywords
不能使用关键字
In the original Rx.NET, the operator that emits a single item and then completes is called Return(T). Since the Java convention is to have a lowercase letter start a method name, this would have been return(T) which is a keyword in Java and thus not available. Therefore, RxJava chose to name this operator just(T). The same limitation exists for the operator Switch, which had to be named switchOnNext. Yet another example is Catch which was named onErrorResumeNext.
在原来的处方。NET中,发出单个项目并完成的操作符称为Return(T)。由于Java约定是用小写字母开始一个方法名,所以这将是return(T),它是Java中的关键字,因此没有可用。因此,RxJava选择将这个操作符命名为just(T)。操作符交换机也存在相同的限制,它必须被命名为switchOnNext。另一个例子是Catch,它被命名为onerrorrecenext。
Type erasure
类型擦除
Many operators that expect the user to provide some function returning a reactive type can’t be overloaded because the type erasure around a Function<T, X> turns such method signatures into duplicates. RxJava chose to name such operators by appending the type as suffix as well:
许多期望用户提供一些返回一个反应类型的函数的操作符不能被重载,因为在一个函数<T, X>的类型擦除会使这种方法签名变成重复。RxJava选择通过将类型作为后缀添加来命名这些操作符:
Flowable flatMap(Function<? super T, ? extends Publisher<? extends R>> mapper)
Flowable flatMapMaybe(Function<? super T, ? extends MaybeSource<? extends R>> mapper)
Type ambiguities
类型模棱两可
Even though certain operators have no problems from type erasure, their signature may turn up being ambiguous, especially if one uses Java 8 and lambdas. For example, there are several overloads of concatWith taking the various other reactive base types as arguments (for providing convenience and performance benefits in the underlying implementation):
尽管某些操作符不会出现类型删除的问题,但它们的签名可能会出现歧义,特别是在使用Java 8和lambdas的情况下。例如,有几个重载的concatWith将各种其他的反应基类型作为参数(为了在底层实现中提供方便和性能好处):
Flowable concatWith(Publisher<? extends T> other);
Flowable concatWith(SingleSource<? extends T> other);
Both Publisher and SingleSource appear as functional interfaces (types with one abstract method) and may encourage users to try to provide a lambda expression:
发布者和SingleSource都显示为功能接口(类型为一个抽象方法),并可能鼓励用户尝试提供lambda表达式:
someSource.concatWith(s -> Single.just(2))
.subscribe(System.out::println, Throwable::printStackTrace);
Unfortunately, this approach doesn’t work and the example does not print 2 at all. In fact, since version 2.1.10, it doesn’t even compile because at least 4 concatWith overloads exist and the compiler finds the code above ambiguous.
不幸的是,这种方法不起作用,而且示例根本不打印2。事实上,自从2.1.10版本以来,它甚至没有编译,因为至少有4个concatWith重载存在,编译器发现上面的代码不明确。
The user in such situations probably wanted to defer some computation until the sameSource has completed, thus the correct unambiguous operator should have been defer:
在这种情况下,用户可能想要推迟一些计算,直到sameSource完成,因此正确的明确的操作符应该被推迟:
someSource.concatWith(Single.defer(() -> Single.just(2)))
.subscribe(System.out::println, Throwable::printStackTrace);
Sometimes, a suffix is added to avoid logical ambiguities that may compile but produce the wrong type in a flow:
有时,添加一个后缀来避免可能编译但在流中产生错误类型的逻辑歧义:
Flowable merge(Publisher<? extends Publisher<? extends T>> sources);
Flowable mergeArray(Publisher<? extends T>… sources);
This can get also ambiguous when functional interface types get involved as the type argument T.
当函数接口类型以类型参数T介入时,这也会变得模糊。
Error handling
错误处理
Dataflows can fail, at which point the error is emitted to the consumer(s). Sometimes though, multiple sources may fail at which point there is a choice whether or not wait for all of them to complete or fail. To indicate this opportunity, many operator names are suffixed with the DelayError words (while others feature a delayError or delayErrors boolean flag in one of their overloads):
数据流可能会失败,此时会向使用者发出错误。有时,多个来源可能会失败,在这一点上,有一个选择是等待他们全部完成还是失败。为了表示这个机会,许多操作符的名称都带有DelayError单词的后缀(而其他的操作符在它们的重载中有一个DelayError或delayErrors boolean标志):
Flowable concat(Publisher<? extends Publisher<? extends T>> sources);
Flowable concatDelayError(Publisher<? extends Publisher<? extends T>> sources);
Of course, suffixes of various kinds may appear together:
当然,各种各样的后缀可能出现在一起:
Flowable concatArrayEagerDelayError(Publisher<? extends T>… sources);
Base class vs base type
基类vs基类型
The base classes can be considered heavy due to the sheer number of static and instance methods on them. RxJava 2’s design was heavily influenced by the Reactive Streams specification, therefore, the library features a class and an interface per each reactive type:
基于静态和实例方法的数量,基类可以被认为是重的。RxJava 2的设计受到了响应流规范的严重影响,因此,该库具有一个类和每个反应类型的接口:
Type Class Interface Consumer
0…N backpressured Flowable Publisher1 Subscriber
0…N unbounded Observable ObservableSource2 Observer
1 element or error Single SingleSource SingleObserver
0…1 element or error Maybe MaybeSource MaybeObserver
0 element or error Completable CompletableSource CompletableObserver
1The org.reactivestreams.Publisher is part of the external Reactive Streams library. It is the main type to interact with other reactive libraries through a standardized mechanism governed by the Reactive Streams specification.
发布者是外部反应流库的一部分。它是通过受反应式流规范控制的标准机制与其他反应性库交互的主要类型。
2The naming convention of the interface was to append Source to the semi-traditional class name. There is no FlowableSource since Publisher is provided by the Reactive Streams library (and subtyping it wouldn’t have helped with interoperation either). These interfaces are, however, not standard in the sense of the Reactive Streams specification and are currently RxJava specific only.
接口的命名约定是将源添加到半传统的类名。因为发布者是由无反应的流库提供的,所以没有FlowableSource(并且子类型也不会帮助进行互操作)。然而,这些接口在无反应流规范的意义上是不标准的,目前只针对RxJava。
Further reading
For further details, consult the wiki.
Communication
Google Group: RxJava
Twitter: @RxJava
GitHub Issues
StackOverflow: rx-java and rx-java2
Gitter.im
Versioning
版本
Version 2.x is now considered stable and final. Version 1.x will be supported for several years along with 2.x. Enhancements and bugfixes will be synchronized between the two in a timely manner.
版本2。x现在被认为是稳定的和最终的。版本1。x将与2。x一起支持数年。增强和错误修复将会在这两者之间及时同步。
Minor 2.x increments (such as 2.1, 2.2, etc) will occur when non-trivial new functionality is added or significant enhancements or bug fixes occur that may have behavioral changes that may affect some edge cases (such as dependence on behavior resulting from a bug). An example of an enhancement that would classify as this is adding reactive pull backpressure support to an operator that previously did not support it. This should be backwards compatible but does behave differently.
当添加了非琐碎的新功能,或者出现了显著的增强或bug修复时,会出现Minor 2.x增量(如2.1、2.2等),这些变化可能会影响某些边缘情况(比如对bug的依赖)。一个可以分类的增强的例子是增加了反应性的反压力支持给一个以前不支持它的操作员。这应该是向后兼容的,但行为方式不同。
Patch 2.x.y increments (such as 2.0.0 -> 2.0.1, 2.3.1 -> 2.3.2, etc) will occur for bug fixes and trivial functionality (like adding a method overload). New functionality marked with an @Beta or @Experimental annotation can also be added in patch releases to allow rapid exploration and iteration of unstable new functionality.
补丁2. x。y增量(比如2.0.0 -> 2.0.1,2.3.1 -> 2.3.2,等等)将会出现在bug修复和琐碎的功能(比如添加一个方法重载)中。用@Beta或@Experimental注释标记的新功能也可以添加到补丁版本中,以允许快速开发和迭代不稳定的新功能。
@Beta
APIs marked with the @Beta annotation at the class or method level are subject to change. They can be modified in any way, or even removed, at any time. If your code is a library itself (i.e. it is used on the CLASSPATH of users outside your own control), you should not use beta APIs, unless you repackage them (e.g. using ProGuard, shading, etc).
在类或方法级别上标记为@Beta注释的api可能会发生更改。它们可以在任何时候被修改,甚至被删除。如果您的代码是一个库本身(也就是说,它是在您自己的控制之外的用户的类路径上使用的),那么您不应该使用beta api,除非您重新打包它们(例如使用ProGuard、shading等)。
@Experimental
实验的
APIs marked with the @Experimental annotation at the class or method level will almost certainly change. They can be modified in any way, or even removed, at any time. You should not use or rely on them in any production code. They are purely to allow broad testing and feedback.
在类或方法级别上标记为@Experimental annotation的api几乎肯定会发生变化。它们可以在任何时候被修改,甚至被删除。您不应该在任何生产代码中使用或依赖它们。它们纯粹是为了允许广泛的测试和反馈。
@Deprecated
APIs marked with the @Deprecated annotation at the class or method level will remain supported until the next major release but it is recommended to stop using them.
io.reactivex.internal.*
All code inside the io.reactivex.internal.* packages is considered private API and should not be relied upon at all. It can change at any time.
@Deprecated(弃用)
在类或方法级别上标记为@Deprecated注释的api将一直支持到下一个主要版本,但建议停止使用它们。
io.reactivex.internal.*
在io.reactivex.internal.*包内的所有代码都被认为是私有API,根本不应该依赖。它随时都可以改变。
Full Documentation 完整文档
Wiki
Javadoc
Binaries
Binaries and dependency information for Maven, Ivy, Gradle and others can be found at http://search.maven.org.
可以在http://search.maven.org上找到Maven、Ivy、Gradle等的二进制文件和依赖信息。
Example for Gradle:
compile ‘io.reactivex.rxjava2:rxjava:x.y.z’
and for Maven:
io.reactivex.rxjava2
rxjava
x.y.z
and for Ivy:
Snapshots are available via https://oss.jfrog.org/libs-snapshot/io/reactivex/rxjava2/rxjava/
repositories {
maven { url ‘https://oss.jfrog.org/libs-snapshot’ }
}
dependencies {
compile ‘io.reactivex.rxjava2:rxjava:2.2.0-SNAPSHOT’
}
Build
To build:
$ git clone git@github.com:ReactiveX/RxJava.git
$ cd RxJava/
$ ./gradlew build
Further details on building can be found on the Getting Started page of the wiki.
关于构建的进一步细节可以在wiki的入门页面上找到。