web-dev-qa-db-ja.com

RxJavaでは、オブザーバブルをチェーンするときに変数を渡す方法は?

RxJavaを使用して非同期操作をチェーンしているため、下流にいくつかの変数を渡したいと思います。

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

よくあるパターンのようですが、それに関する情報が見つかりませんでした。

70
Julian Go

Couchbaseフォーラムから得たアドバイスは、ネストされたオブザーバブルを使用することです。

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

編集:これが最も推奨されると思われるため、これを受け入れられた答えとしてマークします。処理が複雑すぎてすべてをネストできない場合は、関数呼び出しでソリューションを確認することもできます。

55
Julian Go

別の可能性は、op1の結果を変数を含むorg.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オペレータが助けてくれるだろうか?

13
Julian Go

flatmapは2番目の引数を取ることができます:

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

5
Sisyphus

1つの可能性は、関数呼び出しを使用することです。

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); })

しかし、私が間違っている場合は修正しますが、それを行うリアクティブプログラミング方法のようには感じません

5
Julian Go

これを実現するために「グローバル」変数を使用できます。

 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);
     })
1
happyyangyuan

このスレッドのソリューションは機能しますが、複雑なチェーンの場合、コードを読みにくくするため、複数の値を渡す必要があり、すべてのパラメーターを持つプライベートクラスを作成しました。

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);
   })

それが役に立てば幸い

1
josesuero

これは古い質問ですが、RxJava2とラムダを使用すると、次のようなものを使用できます。

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

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

次のフロー(flatmap/map)では、出力ペアは(data1、data2)になります

0
Ndivhuwo