web-dev-qa-db-fra.com

Dans RxJava, comment transmettre une variable lors de l'enchaînement d'observables?

J'enchaîne des opérations asynchrones en utilisant RxJava, et j'aimerais passer une variable en aval:

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

Cela semble être une tendance commune mais je n’ai pas pu trouver d’information à ce sujet.

64
Julian Go

Le conseil que j'ai reçu du forum Couchbase est d'utiliser des observables imbriquées:

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

EDIT: Je vais marquer ceci comme la réponse acceptée car cela semble être la plus recommandée. Si votre traitement est trop complexe pour tout imbriquer, vous pouvez également vérifier la solution avec des appels de fonction.

50
Julian Go

Une autre possibilité consiste à mapper le résultat de op1 à un org.Apache.commons.lang3.Tuple.Pair contenant la variable et à le transmettre:

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

Cela fonctionne mais il est un peu inconfortable d’avoir des variables cachées dans Pair/Triple/... et cela devient très verbeux si vous utilisez la notation Java 6.

Je me demande s’il existe une meilleure solution. Peut-être qu'un opérateur de RxJava pourrait vous aider?

11
Julian Go

Une possibilité serait d'utiliser un appel de fonction:

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

MAIS: corrigez-moi si je me trompe, mais cela ne ressemble pas à la méthode de programmation réactive

4
Julian Go

flatmap peut prendre un deuxième argument:

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

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

3
Sisyphus

Vous pouvez utiliser la variable "globale" pour y parvenir: 

 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

la solution sur ce fil fonctionne, mais pour les chaînes complexes cela rend le code difficile à lire, je devais passer plusieurs valeurs et ce que je fis fut de créer une classe privée avec tous les paramètres.

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

j'espère que ça aide

1
josesuero

Je sais que c’est une vieille question, mais en utilisant RxJava2 & lambda, vous pouvez utiliser quelque chose comme:

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

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

Au prochain flux (flatmap/map), votre paire de résultats sera (data1, data2)

0
Ndivhuwo