Observable类型是惰性的,这意味着它在订阅之前什么都不做。这与eager类型(如Future)不同,后者在创建时表示活动工作。惰性允许Observable组合,避免由于竞态条件下没有缓存而导致的数据丢失。在Future,这不是一个问题,因为单个值可以被缓存,因此,如果该值在组合之前交付了,则将获取该值。如果有一个无限制的流,则需要一个无限制的缓冲区来提供相同的保证。因此,Observable 性是懒惰的,并且在订阅之前不会启动,以便在数据开始流动之前完成所有组合。

实际上,这意味着两件事:

  • Subscription, not construction starts work

由于Observable的惰性,创建它并不会导致任何工作发生(忽略分配可观察对象本身的“工作”)。它所做的就是定义当它最终订阅时应该做什么工作。考虑一个Observable的定义如下:

Observable<T> someData = Observable.create(s -> {
    getDataFromServerWithCallback(args, data -> {
        s.onNext(data);
        s.onCompleted();
    });
})

someData引用现在存在,但getDataFromServerWithCallback还没有被执行。所发生的一切是,Observable的包装器已经被声明为要执行的工作单元,它是Observable范围内的功能。

对于Observable的订阅会导致工作的执行:

someData.subscribe(s -> System.out.println(s));

这种惰性的执行工作由Observable代表。

  • Observables can be reused

因为Observable是惰性的,所以它也意味着一个特定的实例可以被多次调用。继续前面的示例,这意味着我们可以做到以下几点:

someData.subscribe(s -> System.out.println("Subscriber 1: " + s));
someData.subscribe(s -> System.out.println("Subscriber 2: " + s));

现在将会有两个不同的订阅,每个都会调用getDataFromServerWithCallback并发射事件。

这种惰性与异步类型(如Future )不同,Future被创建来代表已经开始启动的任务。一个Future不能被重用(订阅多次以触发工作)。如果对Future 的引用存在,它意味着工作已经在发生。你可以在前面的示例代码中看到那些地方是eager(即热切的)的;getDataFromServerWithCallback方法是eager的,因为它立即执行时调用。通过一个Observable 来包装它,可以使其具有惰性。

这种懒惰在做组合时很有力量。例如:

someData
    .onErrorResumeNext(lazyFallback)
    .subscribe(s -> System.out.println(s));

在本例中,lazyFallback这个Observable代表了可以完成的工作,但是只有在某些东西订阅了它的情况下才会完成,而我们只想在某些数据失败的时候才订阅到它。当然,通过使用函数调用(例如getDataAsFutureA())可以使eager类型变得惰性。

eager和lazy各有优缺点,但RxJava Observable是惰性的。因此,如果你有一个Observable,它不会做任何事情,直到你订阅它。

这个话题在121页的“Embracing Laziness”中有更详细的讨论。

results matching ""

    No results matching ""