RxJava01_RxJava介绍译文

原文: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 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 source = Flowable.fromCallable(() -> {
Thread.sleep(1000); // imitate expensive computation
return “Done”;
});
Flowable runBackground = source.subscribeOn(Schedulers.io());
Flowable 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

猜你喜欢

转载自blog.csdn.net/baopengjian/article/details/80589934