java 使用 RxJava 链接两个改造可观察量

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/30269011/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-11-02 16:48:00  来源:igfitidea点击:

Chain two retrofit observables w/ RxJava

javaandroidretrofitreactive-programmingrx-java

提问by localhost

I want to execute 2 network calls one after another. Both network calls return Observable. Second call uses data from successful result of the first call, method in successful result of second call uses data from bothsuccessful result of the first and of the second call. Also i should be able to handle bothonError "events" differently. How can i achieve this avoiding callback hell like in example below:

我想一个接一个地执行 2 个网络调用。两个网络调用都返回 Observable。从第一个呼叫,方法在第二个呼叫的成功的结果的成功的结果第二呼叫使用数据从数据使用两个第二呼叫的所述第一的成功的结果和。此外,我应该能够以不同的方式处理两个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();
                }
            });

I know about zip, but i want to avoidcreating "Combiner class".

我知道 zip,但我想避免创建“组合器类”。

Update 1.Tried to implement akarnokd's answer:

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

However inside flatMapmethod compiler says it can't resolve methods of authResponse and users (authResponse.getAccessToken(), users.get(0)etc). Im new to rx programming and lambdas - please tell me what's the problem. Anyway code looks much cleaner now.

但是里面flatMap的方法编译器说,它无法解析authResponse和用户(的方法authResponse.getAccessToken()users.get(0)等等)。我是 rx 编程和 lambdas 的新手 - 请告诉我有什么问题。无论如何,代码现在看起来更干净了。

Update 2.

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

Have done it like this, but now my network calls aren't executing at all.

已经这样做了,但现在我的网络调用根本没有执行。

采纳答案by akarnokd

In addition to Anthony R.'s answer, there is a flatMap overload which takes a Func2 and pairs your primary and flattened values for you. In addition, look at the onErrorXXX and onExceptionXXX operators for error manipulation, and chain them with your first and second Observables

除了 Anthony R. 的回答之外,还有一个 flatMap 重载,它采用 Func2 并为您配对您的主要和扁平值。此外,查看 onErrorXXX 和 onExceptionXXX 操作符进行错误操作,并将它们与您的第一个和第二个 Observables 链接起来

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

回答by Anthony R.

Have you looked into flatMap()? If your aversion to it (or zip()) is the need to make an unnecessary class just to hold two objects, android.util.Pair might be an answer. I'm not sure how to get exactly the error handling you're looking for, though.

你研究过 flatMap() 吗?如果您对它(或 zip())的厌恶是需要创建一个不必要的类来保存两个对象,那么 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
          }
        });