web-dev-qa-db-ja.com

RxJavaを使用して2つの改良型オブザーバブルをチェーンする

2つのネットワークコールを順次実行したい。どちらのネットワーク呼び出しもObservableを返します。 2番目の呼び出しは、最初の呼び出しの成功結果のデータを使用し、2番目の呼び出しの成功結果のメソッドは、最初の呼び出しと2番目の呼び出しの成功結果bothのデータを使用します。また、私は両方 onError "イベント"を異なる方法で処理できるはずです。以下の例のようにコールバック地獄を回避してこれをどのように達成できますか?

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

Zipについては知っていますが、avoidで「Combinerクラス」を作成したいと思います。

pdate 1。 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);
                }
            }));
_

ただし、flatMap内のメソッドコンパイラは、authResponseおよびユーザーのメソッド(authResponse.getAccessToken()users.get(0)など)を解決できないと述べています。私はrxプログラミングとラムダの初心者です-何が問題なのか教えてください。とにかく、コードはずっときれいに見えます。

アップデート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);
            }));
_

このように実行しましたが、ネットワークコールがまったく実行されていません。

26
localhost

Anthony R.の回答に加えて、Func2を受け取り、プライマリ値とフラット化された値をペアにするflatMapオーバーロードがあります。さらに、エラー操作のためにonErrorXXXおよびonExceptionXXX演算子を確認し、最初と2番目のオブザーバブルでそれらをチェーンします。

first.onErrorReturn(1)
.flatMap(v -> service(v).onErrorReturn(2), (a, b) -> a + b);
10
akarnokd

FlatMap()を調べましたか?それに対する嫌悪(またはZip())が2つのオブジェクトを保持するためだけに不要なクラスを作成する必要がある場合、Android.util.Pairが答えになる可能性があります。しかし、あなたが探しているエラー処理を正確に取得する方法はわかりません。

       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.