J'essaie de remplacer mon code avec rx-Java. (C'est un très petit code.)
C'est fini et ça marche.
Mais je veux savoir...
Ci-dessous est mon code qui est api manipulation.
avant
Random r = new Random();
boolean apiResult = r.nextBoolean(); // it represents api result. ex. {"result": true} or {"result": false}
if (apiResult == true) {
// do something
System.out.println("result:" + "success");
} else {
// do something
System.out.println("result:" + "failure");
}
après
Random r = new Random();
Observable<Boolean> apiResultStream = Observable.create(new OnSubscribe<Boolean>() {
@Override
public void call(Subscriber<? super Boolean> subscriber) {
// emit true or false
subscriber.onNext(r.nextBoolean());
}
}).cache(1);
// I used filter for split. Is it Rx style?
// success if true emitted.
Observable<Boolean> successStream = apiResultStream
.filter(aBoolean -> aBoolean == true); // here
// failure if false emitted.
Observable<Boolean> failureStream = apiResultStream
.filter(aBoolean -> aBoolean == false); // here
// success flow
successStream
.flatMap(aBoolean -> Observable.just("success"))
// and do something
.subscribe(aString -> System.out.println("result:" + aString));
// failure flow
failureStream
.flatMap(aBoolean -> Observable.just("failure"))
// and do something.
// I want to keep subscriber.
.subscribe(aString -> System.out.println("result:" + aString));
MODIFIER
J'ai presque remplacé. merci pour bon commentaire.
(mais j'ai quelques codes non remplacés. Ils ont beaucoup de callback et if statement.)
Je veux éviter «l'enfer de rappel».
La clé est un type de résultat différent entre 'callSuccessApi' et 'callFailureApi'
avant rx
// callback hell!
callApi(new Callback<Result>(){
@Override
public void success(Result result) {
if (result.Response == true) {
callSuccessApi(new Callback<ResultSuccess>(){
@Override
public void success(ResultSuccess result) {
// and more callbacks...
}
}
} else { // result.Response == false
callFailureApi(new Callback<ResultFailure>(){
@Override
public void success(ResultFailure result) {
// and more callbacks...
}
}
}
}
}
apres avec rx (eviter le callback! Est-ce un bon style de Rx?)
// change 1st api to observable.(I changed other api to observable)
Observable<Result> apiResultStream = Observable.create(new OnSubscribe<Boolean>() {
@Override
public void call(Subscriber<? super Boolean> subscriber) {
callApi(new Callback<Result>(){
@Override
public void success(Result result) {
subscriber.onNext(result);
}
});
}
}).cache(1); // ensure same Observable<Result> for success and failure.
// I used filter for split. Is it Rx style?
// success if result.response == true.
Observable<ResultSuccess> successStream = apiResultStream
.filter(result -> result.response == true); // here
// failure if result.response == false.
Observable<ResultFailure> failureStream = apiResultStream
.filter(result -> result.response == false); // here
// success flow. callSuccessApi return Observable<ResultSuccess>
successStream
.flatMap(result -> callSuccessApi(result))
// and more api call with flatMap...
.subscribe(resultSuccessN -> System.out.println("result:" + resultSuccessN.toString()));
// failure flow. callFailureApi return Observable<ResultFailure>
failureStream
.flatMap(resultFailure -> callFailureApi(result))
// and more api call with flatMap...
.subscribe(resultFailureN -> System.out.println("result:" + resultFailureN.toString()));
désolé pour mon pauvre anglais et longue question.
Mise à jour de mon code
J'ai eu 2 informations importantes dans cette question. (Merci @ Tomáš Dvořák, @Will
code mis à jour
Observable<Result> apiResultStream = Observable.create(new OnSubscribe<Boolean>() {
@Override
public void call(Subscriber<? super Boolean> subscriber) {
callApi(new Callback<Result>() {
@Override
public void success(Result result) {
subscriber.onNext(result);
}
});
}
});
// In this case, I used 'if' for simply and cleanly.
apiResultStream
.subscribe(result -> {
if (result.response == true) {
callSuccessApi(); // this line looks like 'callback'. but I used this for simply and cleanly.
} else {
callFailureApi();
}
});
Il existe de nombreuses façons de le faire et cela dépend vraiment de votre cas d'utilisation. En général, je ne voudrais pas diviser en 2 flux, cela rendrait votre code moins lisible. De plus, je ne suis pas sûr des avantages de l'appel flatMap. Il n'y a rien de mal à faire si des éléments dans un appel de carte.
Voici quelques options:
1 - Pour ajouter la journalisation (un peu comme vos lignes d'impression), j'utilise doOnEach()
apiResultStream
.doOnEach(next -> {
if (next) logger.info("Logging true " + next);
else logger.info(Logging false " + next);
})
.subscribe(....
2 - Le travail que vous effectuez fait partie de votre flux, et vous allez vouloir travailler plus tard sur le flux - utilisez map
apiResultStream
.map(next -> {
if (next) doSomeCallWithNextWhenTrue(next);
else doSomeCallwithNextWhenFalse(next);
})
.subscribe(...
3 - S'il s'agit d'un travail que vous souhaitez effectuer à la fin du pipeline - IE après que tous les flux de transformation ou autres, comme celui-ci est terminé, effectuez l'opération dans l'appel d'abonnement.
apiResultStream
.subscribe(next -> {
if (next) doSomeCallWithNextWhenTrue(next);
else doSomeCallwithNextWhenFalse(next);
});
Le problème est qu’avec un cas d’utilisation aussi simple, il est difficile de suggérer la meilleure option, mais j’apprécie qu’en apprenant à Rx, déterminer comment faire des déclarations conditionnelles peut paraître déroutant. En général, j'utilise simplement map
ou flatMap
lorsque j'appelle une autre méthode qui retourne une Observable
et effectue ma logique.
Mettre à jour
Vous ne savez toujours pas pourquoi vous séparez vos flux. À moins que vous ne deveniez intelligent avec différents threads, le premier appel d'abonnement bloquera le second, ce qui n'est probablement pas ce que vous voulez. En outre, si vous n'appelez pas abonnement plus d'une fois, vous n'avez pas besoin de l'appel cache()
.
Il n'y a rien de mal à utiliser un if statement
dans une map
/flatmap
/subscribe
. Surtout si cela rend votre code plus lisible.
Je voudrais faire ce qui suit:
apiResultStream
.flatMap(result -> {
if (result.response == true) {
return callSuccessApi(result)
}
else {
return callFailureApi(result)
})
//Do any more calls you need
.subscribe(...
Tellement plus propre.
Je suis un peu confus par vos appels System.out.println
dans les abonnements. Est-ce là à des fins de débogage ou de journalisation? Si c'est le cas, faites simplement cela dans la flatMap ci-dessus dans l'instruction if.
J'espère que cela t'aides,
Volonté
Pour éviter le if/else et ne pas rompre la chaîne ™, j'aime utiliser la méthode publier et fusionner pour scinder et fusionner de nouveau le flux:
apiResultStream
.publish(results ->
Observable.merge(
results.filter(result -> result.response == true)
.flatmap(result -> callSuccessApiObservable()),
results.filter(result -> result.response == false)
.flatmap(result -> callFailureApiObservable())
)
)
.subscribe(...