在RxJava中,如何在链接可观察对象时传递变量?


78

我正在使用RxJava链接异步操作,我想向下游传递一些变量:

Observable
   .from(modifications)
   .flatmap( (data1) -> { return op1(data1); })
   ...
   .flatmap( (data2) -> { 
       // How to access data1 here ?
       return op2(data2);
   })

这似乎是一种常见的模式,但是我找不到有关它的信息。

Answers:


63

我从Couchbase论坛获得的建议是使用嵌套的可观察对象:

Observable
   .from(modifications)
   .flatmap( (data1) -> { 
       return op1(data1)
           ...
           .flatmap( (data2) -> { 
               // I can access data1 here
               return op2(data2);
           })
   });

编辑:我将其标记为可接受的答案,因为它似乎是最推荐的。如果处理太复杂而无法嵌套所有内容,则还可以使用函数调用检查解决方案。


这是我经常做的事情,到目前为止效果很好。
2015年

嗯,这跟我“将数据存储在流外”相比并没有太大不同。
ror

18

另一种可能性是将的结果映射op1org.apache.commons.lang3.tuple.Pair包含变量的并将其传递:

Observable
   .from(modifications)
   .flatmap( (data1) -> {
       return op1(data1).map( obj -> { return Pair.of(data1,obj); });
   })
   ...
   .flatmap( (dataPair) -> { 
       // data1 is dataPair.getLeft()
       return op2(dataPair.getRight());
   })

它可以工作,但是将变量隐藏在Pair / Triple / ...中感觉有点不舒服,如果使用Java 6表示法,它会变得很冗长。

我想知道是否有更好的解决方案,也许某些RxJava操作员可以提供帮助?


2
我认为这样做没有任何问题,但是每当我觉得需要去参加Pair课程时,我都会觉得自己做错了。我使用它的次数,一旦我对自己的域有了更好的了解,然后将其重新分解。
2015年

这是我想到的解决方案,尽管它会创建大量的垃圾处理Pair实例,只是要保留在data1旁边obj。我想知道acombine是否可行。
scorpiodawg

7

flatmap可能需要第二个arg:

Observable.just("foo")
                .flatMap(foo -> Observable.range(1, 5), Pair::of)
                .subscribe(pair -> System.out.println("Result: " + pair.getFirst() + " Foo: " + pair.getSecond()));

来源:https : //medium.com/rxjava-tidbits/rxjava-tidbits-1-use-flatmap-and-retain-original-source-value-4ec6a2de52d4


如何导入配对?
Dyno Cris

@DynoCris您可以编写您自己的文件或从某些库中导入它(仅Google Java + Pair)
Sisyphus

6

一种可能性是使用函数调用:

private static Observable<T> myFunc(final Object data1) {
    return op1(data1)
        ...
        .flatmap( (data2) -> { 
            // I can access data1 here
            return op2(data2);
        });
}

Observable
   .from(modifications)
   .flatmap( (data1) -> { return myFunc(data1); })

但是:如果我错了,请纠正我,但是这不像是反应式编程的方式


2
这与您的第一种选择有很大不同吗?
2015年

@Will是的,我想它在功能上类似于使用嵌套调用。毕竟,对于复杂的处理来说,这可能不是一个坏选择。
朱利安(Julian Go)

3

实际上,我们有一个可以简化调用链的库。

https://github.com/pakoito/Komprehensions

添加为Gradle依赖项:

implementation 'io.reactivex.rxjava2:rxjava:2.2.1'
implementation 'com.github.pakoito.Komprehensions:komprehensions-rx2:1.3.2'

用法(科特琳):

val observable = doFlatMap(
    { Observable.from(modifications) },
    { data1 -> op1(data1) },
    { data1, data2 -> op2(data2) },
    { data1, data2, data3 -> op3(data1, data2, data3) }
)

0

此线程上的解决方案有效,但是对于复杂的链,它使代码难以阅读,我不得不传递多个值,而我所做的就是创建一个带有所有参数的私有类,我发现这种方式的代码更具可读性,

private class CommonData{
   private string data1;
   private string data2;

   *getters and setters*
}
...
final CommonData data = new CommonData();
Observable
   .from(modifications)
   .flatmap( (data1) -> { 
       data.setData1(data1);
       return op1(data1); 
   })
   ...
   .flatmap( (data2) -> { 
       data2 = data.getData1() + "data 2... ";
       data.setData2(data2);
       return op2(data2);
   })

希望能帮助到你


2
不幸的是,这可能不是线程安全的(取决于您的代码,RxJava将在多个线程上运行计算)
朱利安(Julian Go

我很困惑,为什么私有的非静态变量会成为线程“不安全”
josesuero

1
如果RxJava创建了多个线程对flatmap()进行数据处理,则即使不是静态的,CommonData实例也会在线程之间共享。(这应该可以通过一些显示当前线程和CommonData值的日志记录进行测试)
朱利安(Julian Go

我需要找到另一个解决方案,因为如果您必须执行以下操作:您将不得不对这两者都进行平面布置。.不好
josesuero

0

我知道这是一个老问题,但是使用RxJava2和lambda,您可以使用类似以下内容的方法:

Observable
.from(modifications)
.flatMap((Function<Data1, ObservableSource<Data2>>) data1 -> {
                        //Get data 2 obeservable

                            return Observable.just(new Data2())
                        }
                    }, Pair::of)

在下一个流程(平面图/地图)上,您的输出对将是(数据1,数据2)


-2

您可以使用“全局”变量来实现此目的:

 Object[] data1Wrapper = new Object[]{null};
 Object[] data2Wrapper = new Object[]{null};
 Observable
    .from(modifications)
    .flatmap(data1 -> {
        data1Wrapper[0] = data1;
        return op1(data1)
     })
      ...
    .flatmap(data2 -> { 
        // I can access data1 here use data1Wrapper[0]
        Object data1 = data1Wrapper[0];
        data2Wrapper[0] = data2;
        return op2(data2);
     })

3
这是个坏建议,不要将数据存储在流之外,请使用SwitchMap或类似方法来传递数据。这是反模式。
lsrom
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.