我在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 /功能方式在我提出的解决方案中解决了我的问题?有没有更好的方法来解决这个问题?
答案 0 :(得分:1)
用户名/密码/ save-flag作为参数传递给execute1()
,标记为final
。然后,在您的匿名嵌套类中,您对这些值进行显式引用,“关闭”它们。由此产生的可观察链具有操作所需的一切。
再次订阅observable将使用原始用户名/密码/ save-flag。