将变量“导入”RxJava链以供日后使用

时间:2017-08-04 15:38:04

标签: android rx-java

我在Android上使用RxJava来执行登录操作。

我需要传递用户名,密码和布尔标志。用户名和密码并发送到服务器进行验证,一旦返回响应,我需要使用该标志来确定下一步该做什么。

由于登录操作是异步的,我想确保当响应返回时我仍然可以访问我在开头传入的用户名,密码和标志。

以下是我编写此代码的最初方式,我认为存在问题:

    public Observable<Result> execute1(final String username, final String password, final boolean shouldSaveUsername) {
    return mLoginNetwork
            .loginWithCredentials(username, password)
            .map(new Func1<Response<Void>, LoginObject>() {
                @Override
                public LoginObject call(Response<Void> response) {
                    if (!response.isSuccessful()) {
                        Exceptions.propagate(new HttpException(response));
                    }

                    return new LoginObject(username, password, shouldSaveUsername);
                }
            })
            .doOnNext(new Action1<LoginObject>() {
                @Override
                public void call(LoginObject loginObject) {
                    if (loginObject.shouldSaveUsername) {
                        saveUsername(username);
                    }
                }
            })
            .flatMap(new Func1<Entitlement, Observable<Result>>() {
                @Override
                public Observable<Result> call(LoginObject loginObject) {
                    return mNetwork
                            .fetchSomething();
                }
            });
}

当我调用execute1()时,它返回一个Observable,我将其缓存然后订阅。如果发生Android配置更改,我取消订阅Observable,但将其保留在缓存中。配置更改完成后,我将Observable从缓存中取出并重新订阅。当我重新订阅loginWithCredentials时,需要再次调用,但是当它返回用户名时,密码和布尔标志将不再存在,因此我无法在我的链中使用它们,这是一个问题。

那么,如何解决这个问题?

我需要一种方法让Observable的输入数据成为Observable的一部分,这样当我缓存Observable时,输入数据也会被缓存。

以下是一个建议的解决方案:

    public Observable<Result> execute2(String username, String password, boolean shouldSaveUsername) {
    return Observable
            .just(new LoginData(username, password, shouldSaveUsername))
            .flatMap(new Func1<LoginData, Observable<LoginData>>() {
                @Override
                public Observable<?> call(final LoginData loginData) {
                    return mLoginNetwork
                            .loginWithCredentials(loginData.getUsername(), loginData.getPassword())
                            .map(new Func1<Response<Void>, LoginData>() {
                                @Override
                                public LoginData call(Response<Void> response) {
                                    if (!response.isSuccessful()) {
                                        Exceptions.propagate(new HttpException(response));
                                    }
                                    return loginData;
                                }
                            });
                }
            })
            .doOnNext(new Action1<LoginData>() {
                @Override
                public void call(LoginData loginData) {
                    if (loginData.shouldSaveUsername) {
                        saveUsername(username);
                    }
                }
            })
            .flatMap(new Func1<LoginData, Observable<Result>>() {
                @Override
                public Observable<Result> call(LoginData loginData) {
                    return mNetwork
                            .fetchSomething();
                }
            });
}

我正在尝试做的是立即使用Observable.just()将输入数据作为流的一部分来获取输入数据并使其成为Observable,然后让其余的下游操作接收它作为一个输入。我假设如果我现在缓存observable并稍后重新订阅,输入数据现在嵌入在我的observable中,并且可以在以后的任何运算符中访问。

我是否以“正常”RxJava /功能方式在我提出的解决方案中解决了我的问题?有没有更好的方法来解决这个问题?

1 个答案:

答案 0 :(得分:1)

用户名/密码/ save-flag作为参数传递给execute1(),标记为final。然后,在您的匿名嵌套类中,您对这些值进行显式引用,“关闭”它们。由此产生的可观察链具有操作所需的一切。

再次订阅observable将使用原始用户名/密码/ save-flag。