【问题标题】:Getting variables "into" RxJava chain for use later将变量“放入”RxJava 链以供以后使用
【发布时间】:2017-08-04 15:38:04
【问题描述】:

我在 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 / 功能方式解决了我提出的解决方案中的问题?有没有更好的方法来解决这个问题?

【问题讨论】:

  • 是的——不使用 observables。这比使用 Thread 或 AsyncTask 并传递参数更简单吗?这段代码绝对不可读。看起来您使用 observable 只是因为它们是很酷的新事物,而不是因为它们实际上为您解决了问题。
  • @GabeSechan 这是一个简化的场景来说明我遇到的概念问题。在我的现实生活场景中,登录部分只是开始。然后我需要再进行 3 次 API 调用来获取更多数据,对其进行过滤和转换,这对于 Rxjava 来说是一个很好的用例。
  • 这可能对获取的数据有意义,但对登录调用本身没有意义(我也对获取的数据表示怀疑——我发现 99% 的 RxJava 使用会降低代码的可读性和可维护的,但我会给它一个没有看到它的怀疑的好处)。但即使是这样,也没有理由将它用于无法使事情更清晰的登录。我会拒绝任何远程代码审查。

标签: android rx-java


【解决方案1】:

用户名/密码/保存标志作为参数传入execute1(),标记为final。然后,在您的匿名嵌套类中,您对这些值进行显式引用,“关闭”它们。生成的可观察链具有运行所需的所有内容。

再次订阅 observable 将使用原来的用户名/密码/保存标志。

【讨论】:

  • 我在最初的问题中没有明确说明这一点,但是具有 execute1() 方法的类在配置更改期间被销毁,并且有资格进行垃圾收集。从 execute1() 方法返回的 observable 缓存在单例中,稍后检索并重新订阅。当它重新订阅时,我不相信最终参数可用了。
  • 参数的存在于可观察对象的生命周期中,而不是创建可观察对象的对象。术语“关闭”是指匿名类在实例化类时创建引用的副本。
  • 你是对的。我运行了几个不同的测试并验证了即使我在重新订阅旧的 observable 时提交了新参数,旧的 observable 在重新订阅时使用其匿名类中的旧参数。我对 Java 工作原理的误解。
  • 所以在我上面给出的示例中,通过添加 final 关键字并直接在匿名类中引用它们来访问参数是“更好”或至少更好的做法,还是传递输入更好从操作员到操作员的数据并将其作为每个匿名类的参数进行访问,直到不再需要它为止?
  • “更好”是一个见仁见智的问题。对于一次性操作,例如您的示例,提供值并关闭它们是简洁和本地化的。
猜你喜欢
  • 1970-01-01
  • 2020-04-07
  • 2015-06-28
  • 1970-01-01
  • 1970-01-01
  • 2011-11-07
  • 2013-08-27
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多