Je veux exécuter 2 appels réseau l'un après l'autre. Les deux appels réseau renvoient Observable. Le deuxième appel utilise les données du résultat réussi du premier appel, la méthode du résultat réussi du deuxième appel utilise les données de les deux résultat réussi du premier et du deuxième appel. De plus, je devrais être capable de gérer les deux onError "événements" différemment. Comment puis-je y parvenir en évitant l'enfer de rappel comme dans l'exemple ci-dessous:
API().auth(email, password)
.subscribeOn(Schedulers.newThread())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Action1<AuthResponse>() {
@Override
public void call(final AuthResponse authResponse) {
API().getUser(authResponse.getAccessToken())
.subscribe(new Action1<List<User>>() {
@Override
public void call(List<User> users) {
doSomething(authResponse, users);
}
}, new Action1<Throwable>() {
@Override
public void call(Throwable throwable) {
onErrorGetUser();
}
});
}
}, new Action1<Throwable>() {
@Override
public void call(Throwable throwable) {
onErrorAuth();
}
});
Je connais Zip, mais je veux éviter créer une "classe de combinaison".
Mise à jour 1. J'ai essayé d'implémenter la réponse d'Akarnokd:
API()
.auth(email, password)
.subscribeOn(Schedulers.newThread())
.observeOn(AndroidSchedulers.mainThread())
.flatMap(authResponse -> API()
.getUser(authResponse.getAccessToken())
.doOnError(throwable -> {
getView().setError(processFail(throwable));
}), ((authResponse, users) -> {
// Ensure returned user is the which was authenticated
if (authResponse.getUserId().equals(users.get(0).getId())) {
SessionManager.getInstance().initSession(email, password, authResponse.getAccessToken(), users.get(0));
getView().toNews();
} else {
getView().setError(R.string.something_went_wrong);
}
}));
Cependant, dans le compilateur de méthodes flatMap
, il ne peut pas résoudre les méthodes d'authResponse et les utilisateurs (authResponse.getAccessToken()
, users.get(0)
etc). Je suis nouveau dans la programmation rx et les lambdas - dites-moi quel est le problème. Quoi qu'il en soit, le code semble beaucoup plus propre maintenant.
mise à jour 2.
API()
.auth(email, password)
.subscribeOn(Schedulers.newThread())
.observeOn(AndroidSchedulers.mainThread())
.doOnError(throwable -> getView().setError(processFail(throwable)))
.flatMap((AuthResponse authResponse) -> API()
.getUser(authResponse.getAccessToken())
.doOnError(throwable -> getView().setError(processFail(throwable))), ((AuthResponse authResponse, List<User> users) -> {
// Ensure returned user is the which was authenticated
if (authResponse.getUserId().equals(users.get(0).getId())) {
SessionManager.getInstance().initSession(email, password, authResponse.getAccessToken(), users.get(0));
getView().toNews();
}
return Observable.just(this);
}));
Je l'ai fait comme ça, mais maintenant mes appels réseau ne s'exécutent pas du tout.
En plus de la réponse d'Anthony R., il existe une surcharge flatMap qui prend un Func2 et associe vos valeurs primaires et aplaties pour vous. En outre, examinez les opérateurs onErrorXXX et onExceptionXXX pour la manipulation des erreurs et enchaînez-les avec vos premier et deuxième observables
first.onErrorReturn(1)
.flatMap(v -> service(v).onErrorReturn(2), (a, b) -> a + b);
Avez-vous examiné flatMap ()? Si votre aversion (ou Zip ()) est la nécessité de créer une classe inutile juste pour contenir deux objets, Android.util.Pair pourrait être une réponse. Cependant, je ne sais pas comment obtenir exactement la gestion des erreurs que vous recherchez.
API().auth(email, password)
.subscribeOn(Schedulers.newThread())
.observeOn(AndroidSchedulers.mainThread())
.flatMap(new Func1<AuthResponse, Observable<List<User>>>() {
@Override
public Observable<List<User>> call(AuthResponse authResponse) {
return API().getUser(authResponse.getAccessToken());
}
}, new Func2<AuthResponse, List<User>, Pair<AuthResponse, List<User>>>() {
@Override
public Pair<AuthResponse, List<User>> call(AuthResponse authResponse, List<User> users) {
return new Pair<>(authResponse, users);
}
}).subscribe(new Action1<Pair<AuthResponse, List<User>>>() {
@Override
public void call(Pair<AuthResponse, List<User>> pair) {
doSomething(pair.first, pair.second);
}
}, new Action1<Throwable>() {
@Override
public void call(Throwable throwable) {
// not sure how to tell which one threw the error
}
});