Zipping是将两个(或多个)流合并到一起的行为,这样一来,每个流中的每个元素都与另一个流中的相应事件相匹配。通过组合每个流中的第一个事件、每个流中的第二个事件等等,产生一个下游事件。因此,只有当所有上游数据源发出一个事件时才会出现事件。当您想要将来自多个相互之间有某种关联的流的结果组合在一起时,这是非常有用的。或者,恰恰相反,两个流相互对立的发射值,但只将它们组合在一起具有业务意义。下面的弹珠图表说明了这是如何工作的:

zip()和zipWith()操作符是等价的。当我们想要流畅地将一个流与另一个流组合在一起时,我们使用前者,就像这样:s1.zipWith(s2,……)。但是,当我们有两个以上的流来组成时,Observable的静态的zip()方法可以操作9个流:

Observable.zip(s1, s2, s3...)

还有许多其他的操作符有实例和静态两种变体——例如,merge()和mergeWith()。要理解zip(),假设您有两个独立的流,但是这些流是彼此同步的。举个例子,考虑一下WeatherStation API,它可以精确地同时公布温度和风速:

interface WeatherStation {
    Observable<Temperature> temperature();
    Observable<Wind> wind();
}

我们必须假设,这两个Observable的事件是同时发射的,并且具有相同的频率。在这一限制下,我们可以通过组合每一对事件安全地连接这两个流。这意味着当一个事件发生在一个流上时,我们必须保持住它直到另一个流上出现事件,反之亦然。zip这个名称意味着我们连接在一起的两个事件流,一个来自左,一个来自右,重复。但是,在更一般的版本中,zip()可以接收9个上游的Observable对象,并且只有当它们全部发出事件时才发出事件。

译者注:因为Java没有这样的方法,而且zip方法在开发语言中的话,返回值一般是元组,即Tuple,所以可以参考Scala、Python语言来理解。

Tuple或者Pair似乎是zip()方法返回的最合适的类型。不幸的是,Java没有元组这个内置数据结构,而RxJava没有任何外部的依赖关系(即没有依赖其他的jar)。因此可以使用Apache Commons Lang, Javaslang或Android SDK中的Pair实现。或者提供一个函数或数据结构,可以将两个事件组合在一起:

class Weather {
    public Weather(Temperature temperature, Wind wind) {
    //...
    }
}
//...
Observable<Temperature> temperatureMeasurements = station.temperature();
Observable<Wind> windMeasurements = station.wind();
temperatureMeasurements
    .zipWith(windMeasurements,
    (temperature, wind) -> new Weather(temperature, wind));

当出现新的Temperature(温度的意思)事件时,zipWith()会等待Wind事件(很显然没有阻塞!),反之亦然。将两个事件传递给我们的自定义lambda表达式中,并将其合并为一个Weather对象。就这样一直循环往复。zip()是用流来描述的,甚至是无限的流。但是,通常您会发现自己使用zipWith()和zip()来进行组合的这些Observable,一般都只会发射一个条目。这种Observable通常是对某些请求或操作的异步响应。在第4章中,我们将详细介绍如何在实际应用程序中使用RxJava。

就目前而言,让我们学习一个例子。我们需要从两个流中生成所有值的笛卡尔积。例如,我们可能有两个Observables,一个是棋盘的行(ranks,1到8),一个是列(files, a to h)。我们想在棋盘上找到所有可能的64个方块:

Observable<Integer> oneToEight = Observable.range(1, 8);
Observable<String> ranks = oneToEight
    .map(Object::toString);
Observable<String> files = oneToEight
    .map(x -> 'a' + x - 1)
    .map(ascii -> (char)ascii.intValue())
    .map(ch -> Character.toString(ch));
Observable<String> squares = files
    .flatMap(file -> ranks.map(rank -> file + rank));

square这个Observable 将发射64个事件:一个Observable发射1~8,一个发射a~h,hen 所以最终的结果无非就是a1,a2,a3...a8,b1,b2..h7,h8。这是flatMap()的另一个有趣的例子,对于每个列(file),在该列中生成所有可能的squares的值。现在我们来看一个更现实的例子它也使用了笛卡尔积。假设你想在某个城市计划一天的假期,天气晴好,机票和酒店都很便宜。为了做到这一点,我们将把几个数据流合并起来,并得出所有可能的结果:

import java.time.LocalDate;
Observable<LocalDate> nextTenDays =
    Observable
        .range(1, 10)
        .map(i -> LocalDate.now().plusDays(i));
Observable<Vacation> possibleVacations = Observable
    .just(City.Warsaw, City.London, City.Paris)
    .flatMap(city -> nextTenDays.map(date -> new Vacation(city, date))
    .flatMap(vacation ->
        Observable.zip(
            vacation.weather().filter(Weather::isSunny),
            vacation.cheapFlightFrom(City.NewYork),
            vacation.cheapHotel(),
            (w, f, h) -> vacation
        ));

Vacation类:

class Vacation {
    private final City where;
    private final LocalDate when;
    Vacation(City where, LocalDate when) {
        this.where = where;
        this.when = when;
    }
    public Observable<Weather> weather() {
        //...
    }
    public Observable<Flight> cheapFlightFrom(City from) {
        //...
    }
    public Observable<Hotel> cheapHotel() {
        //...
    }
}

在前面的代码中发生了很多事情。首先,我们使用range()和map()的组合来生成所有日期,从明天到第10天。然后,我们将这些天与三个城市flatMap——我们不希望在这里使用zip(),因为我们需要所有可能的日期和城市对元组对的组合。对于每一对这样的组合,我们创建一个包含它门的Vacation 类的实例。现在,真正的逻辑是:我们将三个Observables zip压缩在一起:Observable<Weather> , Observable<Flight>和Observable<Hotel>。最后的这两个应该返回一个0或一个结果,这取决于是否为这个city(城市)/date(日期)找到了便宜的Flight(航班)或Hotel(酒店),尽管Observable<Weather>总会返回一些东西,但我们还是使用filter()来过滤掉不是晴天的日子。因此,我们最后得到了三个流的zip()操作,每个流都会发射0或者一个事件条目。如果上游Observable的任何一个完成,zip()也会提前完成,并提早丢弃其他的流(因为zip函数必须得让所有的上层Observable都发射一个事件,它才有事件往下游推送):由于此属性,如果没有任何满足条件的天气、航班或酒店,则zip()的也就不会发射任何的条目。这给服务方法为我们留下了一系列的可能的假期计划。

不要惊讶于zip函数的最后一个参数,它都没有考虑该函数的入参的值:(w, f, h) -> vacation。一个输出的假期流列出了所有可能的假期计划。然而,对于每个假期,我们都要确保天气好、航班便宜和酒店存在。如果所有这些条件都满足,我们就返回度假的实例;否则,zip将不会调用我们的lambda表达式。

results matching ""

    No results matching ""