Tengo el siguiente código:

    final Observable<String> a = Observable.just("a1", "a2");   
    final Observable<String> b = Observable.just("b1");

    final Observable<String> c = Observable.combineLatest(a, b, (first, second) -> first + second);

    c.subscribe(res -> System.out.println(res));

¿Cuál es el resultado esperado? Yo hubiera esperado

a1b1
a2b1

Pero la salida real es

a2b1

¿Tiene sentido? ¿Cuál es el operador correcto para generar la secuencia esperada?

2
Carsten 20 feb. 2018 a las 18:36

2 respuestas

La mejor respuesta

Como debe implicar el nombre del operador, combina el último valor de cada fuente. Si las fuentes son síncronas o muy rápidas, esto podría significar que una o más fuentes se ejecutarán hasta su finalización y el operador recordará solo los últimos valores de cada una. Debe intercalar los valores de origen de alguna manera, como tener fuentes asincrónicas con una gran cantidad de tiempo entre elementos y evitar la superposición de elementos de múltiples fuentes.

La secuencia esperada se puede generar de dos maneras, dependiendo de cuál fue su intención original. Por ejemplo, si desea todas las combinaciones cruzadas, use flatMap:

a.flatMap(aValue -> b, (aValue, bValue) -> first + second)
.subscribe(System.out::println);

Si b es algo costoso de recrear, almacénelo en caché:

Observable<String> cachedB = b.cache();
a.flatMap(aValue -> cachedB, (aValue, bValue) -> first + second)
.subscribe(System.out::println);
1
akarnokd 20 feb. 2018 a las 18:22

¡Buena pregunta! Parece quizás una condición de carrera. combineLatest no generará nada hasta que ambas fuentes hayan emitido, y parece que cuando b genera su salida, a ya ha pasado a su segundo elemento. En una aplicación del "mundo real" con eventos asincrónicos espaciados en el tiempo, probablemente obtendría el comportamiento que desea.

Si puede soportar la espera, una solución sería retrasar un poco las salidas de a. Con un poco más de trabajo, podría retrasar solo la primera salida (vea las diversas sobrecargas del operador delay). También me di cuenta de que hay un operador delaySubscription que probablemente funcionaría (retrasa tu suscripción a a hasta que b emita algo). Estoy seguro de que hay otras soluciones, quizás mejores (todavía estoy aprendiendo).

1
Robert Lewis 20 feb. 2018 a las 16:07