web-dev-qa-db-fra.com

Chaîne deux observables rétrofit w / RxJava

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.

26
localhost

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);
10
akarnokd

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
          }
        });
15
Anthony R.